* support/regression/Makefile.in,
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) do if (options.verboseAsm) {x;} while(0)
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                         AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC     emitcode("clr","c")
170 #define SETC     emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227         }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_OP_ACCUSE (op))
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_OP_ACCUSE (op))
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_OP_ACCUSE (op))
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_OP_ACCUSE (op))
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerializes an object                          */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic))
908         {
909           sym_link *from_type = operandType(IC_RIGHT(ic));
910           aop->aopu.aop_immd.from_cast_remat = 1;
911           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
912           ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
913           continue;
914         }
915       else break;
916
917       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
918     }
919
920   if (val)
921     {
922       SNPRINTF (buffer, sizeof(buffer),
923                 "(%s %c 0x%06x)",
924                 OP_SYMBOL (IC_LEFT (ic))->rname,
925                 val >= 0 ? '+' : '-',
926                 abs (val) & 0xffffff);
927     }
928   else
929     {
930       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
931         {
932           SNPRINTF(buffer, sizeof(buffer),
933                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
934         }
935       else
936         {
937           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
938         }
939     }
940
941   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
942   /* set immd2 field if required */
943   if (aop->aopu.aop_immd.from_cast_remat)
944     {
945       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
946       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
947     }
948
949   return aop;
950 }
951
952 /*-----------------------------------------------------------------*/
953 /* aopHasRegs - returns true if aop has regs between from-to       */
954 /*-----------------------------------------------------------------*/
955 static int aopHasRegs(asmop *aop, int from, int to)
956 {
957     int size =0;
958
959     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
960
961     for (; size < aop->size ; size++) {
962         int reg;
963         for (reg = from ; reg <= to ; reg++)
964             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
965     }
966     return 0;
967 }
968
969 /*-----------------------------------------------------------------*/
970 /* regsInCommon - two operands have some registers in common       */
971 /*-----------------------------------------------------------------*/
972 static bool
973 regsInCommon (operand * op1, operand * op2)
974 {
975   symbol *sym1, *sym2;
976   int i;
977
978   /* if they have registers in common */
979   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
980     return FALSE;
981
982   sym1 = OP_SYMBOL (op1);
983   sym2 = OP_SYMBOL (op2);
984
985   if (sym1->nRegs == 0 || sym2->nRegs == 0)
986     return FALSE;
987
988   for (i = 0; i < sym1->nRegs; i++)
989     {
990       int j;
991       if (!sym1->regs[i])
992         continue;
993
994       for (j = 0; j < sym2->nRegs; j++)
995         {
996           if (!sym2->regs[j])
997             continue;
998
999           if (sym2->regs[j] == sym1->regs[i])
1000             return TRUE;
1001         }
1002     }
1003
1004   return FALSE;
1005 }
1006
1007 /*-----------------------------------------------------------------*/
1008 /* operandsEqu - equivalent                                        */
1009 /*-----------------------------------------------------------------*/
1010 static bool
1011 operandsEqu (operand * op1, operand * op2)
1012 {
1013   symbol *sym1, *sym2;
1014
1015   /* if they're not symbols */
1016   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1017     return FALSE;
1018
1019   sym1 = OP_SYMBOL (op1);
1020   sym2 = OP_SYMBOL (op2);
1021
1022   /* if both are itemps & one is spilt
1023      and the other is not then false */
1024   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1025       sym1->isspilt != sym2->isspilt)
1026     return FALSE;
1027
1028   /* if they are the same */
1029   if (sym1 == sym2)
1030     return TRUE;
1031
1032   /* if they have the same rname */
1033   if (sym1->rname[0] && sym2->rname[0] &&
1034       strcmp (sym1->rname, sym2->rname) == 0 &&
1035       !(IS_PARM (op2) && IS_ITEMP (op1)))
1036     return TRUE;
1037
1038   /* if left is a tmp & right is not */
1039   if (IS_ITEMP (op1) &&
1040       !IS_ITEMP (op2) &&
1041       sym1->isspilt &&
1042       (sym1->usl.spillLoc == sym2))
1043     return TRUE;
1044
1045   if (IS_ITEMP (op2) &&
1046       !IS_ITEMP (op1) &&
1047       sym2->isspilt &&
1048       sym1->level > 0 &&
1049       (sym2->usl.spillLoc == sym1))
1050     return TRUE;
1051
1052   /* are they spilt to the same location */
1053   if (IS_ITEMP (op2) &&
1054       IS_ITEMP (op1) &&
1055       sym2->isspilt &&
1056       sym1->isspilt &&
1057       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1058     return TRUE;
1059
1060   return FALSE;
1061 }
1062
1063 /*-----------------------------------------------------------------*/
1064 /* sameRegs - two asmops have the same registers                   */
1065 /*-----------------------------------------------------------------*/
1066 static bool
1067 sameRegs (asmop * aop1, asmop * aop2)
1068 {
1069   int i;
1070
1071   if (aop1 == aop2)
1072     {
1073       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1074         {
1075           return FALSE;
1076         }
1077       return TRUE;
1078     }
1079
1080   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1081     return FALSE;
1082
1083   if (aop1->type != aop2->type)
1084     return FALSE;
1085
1086   if (aop1->size != aop2->size)
1087     return FALSE;
1088
1089   for (i = 0; i < aop1->size; i++)
1090     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1091       return FALSE;
1092
1093   return TRUE;
1094 }
1095
1096 /*-----------------------------------------------------------------*/
1097 /* aopOp - allocates an asmop for an operand  :                    */
1098 /*-----------------------------------------------------------------*/
1099 static void
1100 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1101 {
1102   asmop *aop;
1103   symbol *sym;
1104   int i;
1105
1106   if (!op)
1107     return;
1108
1109   /* if this a literal */
1110   if (IS_OP_LITERAL (op))
1111     {
1112       op->aop = aop = newAsmop (AOP_LIT);
1113       aop->aopu.aop_lit = op->operand.valOperand;
1114       aop->size = getSize (operandType (op));
1115       return;
1116     }
1117
1118   /* if already has a asmop then continue */
1119   if (op->aop)
1120     {
1121       if ((op->aop->type == AOP_DPTR && useDP2)
1122           || (op->aop->type == AOP_DPTR2 && !useDP2))
1123         op->aop = NULL;
1124       else
1125         {
1126           op->aop->allocated++;
1127           return;
1128         }
1129     }
1130
1131   /* if the underlying symbol has a aop */
1132   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1133     {
1134       op->aop = OP_SYMBOL (op)->aop;
1135       if ((op->aop->type == AOP_DPTR && useDP2)
1136           || (op->aop->type == AOP_DPTR2 && !useDP2))
1137         op->aop = NULL;
1138       else
1139         {
1140           op->aop->allocated++;
1141           return;
1142         }
1143     }
1144
1145   /* if this is a true symbol */
1146   if (IS_TRUE_SYMOP (op))
1147     {
1148       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1149       return;
1150     }
1151
1152   /* this is a temporary : this has
1153      only five choices :
1154      a) register
1155      b) spillocation
1156      c) rematerialize
1157      d) conditional
1158      e) can be a return use only */
1159
1160   sym = OP_SYMBOL (op);
1161
1162   /* if the type is a conditional */
1163   if (sym->regType == REG_CND)
1164     {
1165       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1166       aop->size = 0;
1167       return;
1168     }
1169
1170   /* if it is spilt then two situations
1171      a) is rematerialize
1172      b) has a spill location */
1173   if (sym->isspilt || sym->nRegs == 0)
1174     {
1175
1176       /* rematerialize it NOW */
1177       if (sym->remat)
1178         {
1179           sym->aop = op->aop = aop = aopForRemat (sym);
1180           aop->size = getSize (sym->type);
1181           return;
1182         }
1183
1184       if (sym->accuse)
1185         {
1186           int i;
1187           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1188           aop->size = getSize (sym->type);
1189           for (i = 0; i < 2; i++)
1190             aop->aopu.aop_str[i] = accUse[i];
1191           return;
1192         }
1193
1194       if (sym->ruonly)
1195         {
1196           unsigned i;
1197
1198           if (useDP2)
1199             {
1200               /* a AOP_STR uses DPTR, but DPTR is already in use;
1201                * we're just hosed.
1202                */
1203                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1204             }
1205
1206           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1207           aop->size = getSize (sym->type);
1208           for (i = 0; i < fReturnSizeDS390; i++)
1209             aop->aopu.aop_str[i] = fReturn[i];
1210           return;
1211         }
1212
1213       if (sym->dptr) { /* has been allocated to a DPTRn */
1214           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1215           aop->size = getSize (sym->type);
1216           aop->aopu.dptr = sym->dptr;
1217           return ;
1218       }
1219
1220       if (sym->usl.spillLoc)
1221         {
1222           asmop *oldAsmOp = NULL;
1223
1224           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1225             {
1226               /* force a new aop if sizes differ */
1227               oldAsmOp = sym->usl.spillLoc->aop;
1228               sym->usl.spillLoc->aop = NULL;
1229             }
1230           sym->aop = op->aop = aop =
1231                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1232           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1233             {
1234               /* Don't reuse the new aop, go with the last one */
1235               sym->usl.spillLoc->aop = oldAsmOp;
1236             }
1237           aop->size = getSize (sym->type);
1238           return;
1239         }
1240
1241       /* else must be a dummy iTemp */
1242       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1243       aop->size = getSize (sym->type);
1244       return;
1245     }
1246
1247   /* if the type is a bit register */
1248   if (sym->regType == REG_BIT)
1249     {
1250       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1251       aop->size = sym->nRegs;//1???
1252       aop->aopu.aop_reg[0] = sym->regs[0];
1253       aop->aopu.aop_dir = sym->regs[0]->name;
1254       return;
1255     }
1256
1257   /* must be in a register */
1258   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1259   aop->size = sym->nRegs;
1260   for (i = 0; i < sym->nRegs; i++)
1261     aop->aopu.aop_reg[i] = sym->regs[i];
1262 }
1263
1264 /*-----------------------------------------------------------------*/
1265 /* freeAsmop - free up the asmop given to an operand               */
1266 /*-----------------------------------------------------------------*/
1267 static void
1268 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1269 {
1270   asmop *aop;
1271
1272   if (!op)
1273     aop = aaop;
1274   else
1275     aop = op->aop;
1276
1277   if (!aop)
1278     return;
1279
1280   aop->allocated--;
1281
1282   if (aop->allocated)
1283     goto dealloc;
1284
1285   /* depending on the asmop type only three cases need work
1286      AOP_R0, AOP_R1 & AOP_STK */
1287   switch (aop->type)
1288     {
1289     case AOP_R0:
1290       if (_G.r0Pushed)
1291         {
1292           if (pop)
1293             {
1294               emitcode ("pop", "ar0");
1295               _G.r0Pushed--;
1296             }
1297         }
1298       bitVectUnSetBit (ic->rUsed, R0_IDX);
1299       break;
1300
1301     case AOP_R1:
1302       if (_G.r1Pushed)
1303         {
1304           if (pop)
1305             {
1306               emitcode ("pop", "ar1");
1307               _G.r1Pushed--;
1308             }
1309         }
1310       bitVectUnSetBit (ic->rUsed, R1_IDX);
1311       break;
1312
1313     case AOP_STK:
1314       {
1315         int sz = aop->size;
1316         int stk = aop->aopu.aop_stk + aop->size;
1317         bitVectUnSetBit (ic->rUsed, R0_IDX);
1318         bitVectUnSetBit (ic->rUsed, R1_IDX);
1319
1320         getFreePtr (ic, &aop, FALSE);
1321
1322         if (options.stack10bit)
1323           {
1324             /* I'm not sure what to do here yet... */
1325             /* #STUB */
1326             fprintf (stderr,
1327                      "*** Warning: probably generating bad code for "
1328                      "10 bit stack mode.\n");
1329           }
1330
1331         if (stk)
1332           {
1333             emitcode ("mov", "a,_bp");
1334             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1335             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1336           }
1337         else
1338           {
1339             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1340           }
1341
1342         while (sz--)
1343           {
1344             emitcode ("pop", "acc");
1345             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1346             if (!sz)
1347               break;
1348             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1349           }
1350         op->aop = aop;
1351         freeAsmop (op, NULL, ic, TRUE);
1352         if (_G.r1Pushed)
1353           {
1354             emitcode ("pop", "ar1");
1355             _G.r1Pushed--;
1356           }
1357         if (_G.r0Pushed)
1358           {
1359             emitcode ("pop", "ar0");
1360             _G.r0Pushed--;
1361           }
1362       }
1363     case AOP_DPTR2:
1364         if (_G.dptr1InUse) {
1365             emitcode ("pop","dpx1");
1366             emitcode ("pop","dph1");
1367             emitcode ("pop","dpl1");
1368         }
1369         break;
1370     case AOP_DPTR:
1371         if (_G.dptrInUse) {
1372             emitcode ("pop","dpx");
1373             emitcode ("pop","dph");
1374             emitcode ("pop","dpl");
1375         }
1376         break;
1377     }
1378
1379 dealloc:
1380   /* all other cases just dealloc */
1381   if (op)
1382     {
1383       op->aop = NULL;
1384       if (IS_SYMOP (op))
1385         {
1386           OP_SYMBOL (op)->aop = NULL;
1387           /* if the symbol has a spill */
1388           if (SPIL_LOC (op))
1389             SPIL_LOC (op)->aop = NULL;
1390         }
1391     }
1392 }
1393
1394 #define DEFAULT_ACC_WARNING 0
1395 static int saveAccWarn = DEFAULT_ACC_WARNING;
1396
1397
1398 /*-----------------------------------------------------------------*/
1399 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1400 /*                 clobber the accumulator                         */
1401 /*-----------------------------------------------------------------*/
1402 static bool
1403 aopGetUsesAcc (operand * oper, int offset)
1404 {
1405   asmop * aop = AOP (oper);
1406
1407   if (offset > (aop->size - 1))
1408     return FALSE;
1409
1410   switch (aop->type)
1411     {
1412
1413     case AOP_R0:
1414     case AOP_R1:
1415       if (aop->paged)
1416         return TRUE;
1417       return FALSE;
1418     case AOP_DPTR:
1419     case AOP_DPTR2:
1420     case AOP_DPTRn:
1421       return TRUE;
1422     case AOP_IMMD:
1423       return FALSE;
1424     case AOP_DIR:
1425       return FALSE;
1426     case AOP_REG:
1427       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1428       return FALSE;
1429     case AOP_CRY:
1430       return TRUE;
1431     case AOP_ACC:
1432       if (offset)
1433         return FALSE;
1434       return TRUE;
1435     case AOP_LIT:
1436       return FALSE;
1437     case AOP_STR:
1438       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1439         return TRUE;
1440       return FALSE;
1441     case AOP_DUMMY:
1442       return FALSE;
1443     default:
1444       /* Error case --- will have been caught already */
1445       wassert(0);
1446       return FALSE;
1447     }
1448 }
1449
1450 /*-------------------------------------------------------------------*/
1451 /* aopGet - for fetching value of the aop                            */
1452 /*                                                                   */
1453 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1454 /* in the accumulator. Set it to the name of a free register         */
1455 /* if acc must be preserved; the register will be used to preserve   */
1456 /* acc temporarily and to return the result byte.                    */
1457 /*-------------------------------------------------------------------*/
1458 static char *
1459 aopGet (operand * oper,
1460         int   offset,
1461         bool  bit16,
1462         bool  dname,
1463         char  *saveAcc)
1464 {
1465   asmop * aop = AOP (oper);
1466
1467   /* offset is greater than
1468      size then zero */
1469   if (offset > (aop->size - 1) &&
1470       aop->type != AOP_LIT)
1471     return zero;
1472
1473   /* depending on type */
1474   switch (aop->type)
1475     {
1476     case AOP_DUMMY:
1477       return zero;
1478
1479     case AOP_R0:
1480     case AOP_R1:
1481       /* if we need to increment it */
1482       while (offset > aop->coff)
1483         {
1484           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1485           aop->coff++;
1486         }
1487
1488       while (offset < aop->coff)
1489         {
1490           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1491           aop->coff--;
1492         }
1493
1494       aop->coff = offset;
1495       if (aop->paged)
1496         {
1497           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1498           return (dname ? "acc" : "a");
1499         }
1500       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1501       return Safe_strdup(buffer);
1502
1503     case AOP_DPTRn:
1504         assert(offset <= 3);
1505         return dptrn[aop->aopu.dptr][offset];
1506
1507     case AOP_DPTR:
1508     case AOP_DPTR2:
1509
1510       if (aop->type == AOP_DPTR2)
1511         {
1512           genSetDPTR (1);
1513         }
1514
1515       if (saveAcc)
1516         {
1517             TR_AP("#1");
1518 //          if (aop->type != AOP_DPTR2)
1519 //          {
1520 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1521 //              emitcode(";", "spanky: saveAcc for DPTR");
1522 //          }
1523
1524             emitcode ("xch", "a, %s", saveAcc);
1525         }
1526
1527       _flushLazyDPS ();
1528
1529       while (offset > aop->coff)
1530         {
1531           emitcode ("inc", "dptr");
1532           aop->coff++;
1533         }
1534
1535       while (offset < aop->coff)
1536         {
1537           emitcode ("lcall", "__decdptr");
1538           aop->coff--;
1539         }
1540
1541       aop->coff = offset;
1542       if (aop->code)
1543         {
1544           emitcode ("clr", "a");
1545           emitcode ("movc", "a,@a+dptr");
1546         }
1547       else
1548         {
1549           emitcode ("movx", "a,@dptr");
1550         }
1551
1552       if (aop->type == AOP_DPTR2)
1553         {
1554           genSetDPTR (0);
1555         }
1556
1557       if (saveAcc)
1558         {
1559           TR_AP("#2");
1560           emitcode ("xch", "a, %s", saveAcc);
1561 //        if (strcmp(saveAcc, "_ap"))
1562 //          {
1563 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1564 //          }
1565
1566           return saveAcc;
1567         }
1568       return (dname ? "acc" : "a");
1569
1570     case AOP_IMMD:
1571       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1572         {
1573           SNPRINTF(buffer, sizeof(buffer),
1574                    "%s",aop->aopu.aop_immd.aop_immd2);
1575         }
1576       else if (bit16)
1577         {
1578           SNPRINTF(buffer, sizeof(buffer),
1579                    "#%s", aop->aopu.aop_immd.aop_immd1);
1580         }
1581       else if (offset)
1582         {
1583           switch (offset) {
1584           case 1:
1585               tsprintf(buffer, sizeof(buffer),
1586                        "#!his",aop->aopu.aop_immd.aop_immd1);
1587               break;
1588           case 2:
1589               tsprintf(buffer, sizeof(buffer),
1590                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1591               break;
1592           case 3:
1593               tsprintf(buffer, sizeof(buffer),
1594                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1595               break;
1596           default: /* should not need this (just in case) */
1597               SNPRINTF (buffer, sizeof(buffer),
1598                         "#(%s >> %d)",
1599                        aop->aopu.aop_immd.aop_immd1,
1600                        offset * 8);
1601           }
1602         }
1603       else
1604         {
1605           SNPRINTF (buffer, sizeof(buffer),
1606                     "#%s",
1607                     aop->aopu.aop_immd.aop_immd1);
1608         }
1609       return Safe_strdup(buffer);
1610
1611     case AOP_DIR:
1612       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1613         {
1614           SNPRINTF (buffer, sizeof(buffer),
1615                     "(%s >> %d)",
1616                     aop->aopu.aop_dir, offset * 8);
1617         }
1618       else if (offset)
1619         {
1620           SNPRINTF (buffer, sizeof(buffer),
1621                     "(%s + %d)",
1622                     aop->aopu.aop_dir,
1623                     offset);
1624         }
1625       else
1626         {
1627           SNPRINTF (buffer, sizeof(buffer),
1628                     "%s",
1629                     aop->aopu.aop_dir);
1630         }
1631
1632       return Safe_strdup(buffer);
1633
1634     case AOP_REG:
1635       if (dname)
1636         return aop->aopu.aop_reg[offset]->dname;
1637       else
1638         return aop->aopu.aop_reg[offset]->name;
1639
1640     case AOP_CRY:
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("clr", "a");
1643       emitcode ("rlc", "a");
1644       return (dname ? "acc" : "a");
1645
1646     case AOP_ACC:
1647       if (!offset && dname)
1648         return "acc";
1649       return aop->aopu.aop_str[offset];
1650
1651     case AOP_LIT:
1652       return aopLiteral (aop->aopu.aop_lit, offset);
1653
1654     case AOP_STR:
1655       aop->coff = offset;
1656       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1657           dname)
1658         return "acc";
1659
1660       return aop->aopu.aop_str[offset];
1661
1662     }
1663
1664   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1665           "aopget got unsupported aop->type");
1666   exit (1);
1667
1668   return NULL;  // not reached, but makes compiler happy.
1669 }
1670
1671 /*-----------------------------------------------------------------*/
1672 /* aopPut - puts a string for a aop and indicates if acc is in use */
1673 /*-----------------------------------------------------------------*/
1674 static bool
1675 aopPut (operand * result, const char *s, int offset)
1676 {
1677   bool bvolatile = isOperandVolatile (result, FALSE);
1678   bool accuse = FALSE;
1679   asmop * aop = AOP (result);
1680   const char *d = NULL;
1681
1682   if (aop->size && offset > (aop->size - 1))
1683     {
1684       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1685               "aopPut got offset > aop->size");
1686       exit (1);
1687     }
1688
1689   /* will assign value to value */
1690   /* depending on where it is ofcourse */
1691   switch (aop->type)
1692     {
1693     case AOP_DUMMY:
1694       MOVA (s);         /* read s in case it was volatile */
1695       accuse = TRUE;
1696       break;
1697
1698     case AOP_DIR:
1699       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1700         {
1701           SNPRINTF (buffer, sizeof(buffer),
1702                     "(%s >> %d)",
1703                     aop->aopu.aop_dir, offset * 8);
1704         }
1705       else if (offset)
1706         {
1707           SNPRINTF (buffer, sizeof(buffer),
1708                     "(%s + %d)",
1709                     aop->aopu.aop_dir, offset);
1710         }
1711       else
1712         {
1713           SNPRINTF (buffer, sizeof(buffer),
1714                     "%s",
1715                     aop->aopu.aop_dir);
1716         }
1717
1718       if (strcmp (buffer, s) || bvolatile)
1719         {
1720           emitcode ("mov", "%s,%s", buffer, s);
1721         }
1722       if (!strcmp (buffer, "acc"))
1723         {
1724           accuse = TRUE;
1725         }
1726       break;
1727
1728     case AOP_REG:
1729       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1730           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1731         {
1732           if (*s == '@' ||
1733               strcmp (s, "r0") == 0 ||
1734               strcmp (s, "r1") == 0 ||
1735               strcmp (s, "r2") == 0 ||
1736               strcmp (s, "r3") == 0 ||
1737               strcmp (s, "r4") == 0 ||
1738               strcmp (s, "r5") == 0 ||
1739               strcmp (s, "r6") == 0 ||
1740               strcmp (s, "r7") == 0)
1741             {
1742               emitcode ("mov", "%s,%s",
1743                         aop->aopu.aop_reg[offset]->dname, s);
1744             }
1745           else
1746             {
1747               emitcode ("mov", "%s,%s",
1748                         aop->aopu.aop_reg[offset]->name, s);
1749             }
1750         }
1751       break;
1752
1753     case AOP_DPTRn:
1754         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1755         break;
1756
1757     case AOP_DPTR:
1758     case AOP_DPTR2:
1759
1760       if (aop->type == AOP_DPTR2)
1761         {
1762           genSetDPTR (1);
1763         }
1764       _flushLazyDPS ();
1765
1766       if (aop->code)
1767         {
1768           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1769                   "aopPut writing to code space");
1770           exit (1);
1771         }
1772
1773       while (offset > aop->coff)
1774         {
1775           aop->coff++;
1776           emitcode ("inc", "dptr");
1777         }
1778
1779       while (offset < aop->coff)
1780         {
1781           aop->coff--;
1782           emitcode ("lcall", "__decdptr");
1783         }
1784
1785       aop->coff = offset;
1786
1787       /* if not in accumulator */
1788       MOVA (s);
1789
1790       emitcode ("movx", "@dptr,a");
1791
1792       if (aop->type == AOP_DPTR2)
1793         {
1794           genSetDPTR (0);
1795         }
1796       break;
1797
1798     case AOP_R0:
1799     case AOP_R1:
1800       while (offset > aop->coff)
1801         {
1802           aop->coff++;
1803           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1804         }
1805       while (offset < aop->coff)
1806         {
1807           aop->coff--;
1808           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1809         }
1810       aop->coff = offset;
1811
1812       if (aop->paged)
1813         {
1814           MOVA (s);
1815           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1816         }
1817       else if (*s == '@')
1818         {
1819           MOVA (s);
1820           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1821         }
1822       else if (strcmp (s, "r0") == 0 ||
1823                strcmp (s, "r1") == 0 ||
1824                strcmp (s, "r2") == 0 ||
1825                strcmp (s, "r3") == 0 ||
1826                strcmp (s, "r4") == 0 ||
1827                strcmp (s, "r5") == 0 ||
1828                strcmp (s, "r6") == 0 ||
1829                strcmp (s, "r7") == 0)
1830         {
1831           char buffer[10];
1832           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1833           emitcode ("mov", "@%s,%s",
1834                     aop->aopu.aop_ptr->name, buffer);
1835         }
1836       else
1837         {
1838           emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1839         }
1840       break;
1841
1842     case AOP_STK:
1843       if (strcmp (s, "a") == 0)
1844         {
1845           emitcode ("push", "acc");
1846         }
1847       else if (*s=='@')
1848         {
1849           MOVA(s);
1850           emitcode ("push", "acc");
1851         }
1852       else if (strcmp (s, "r0") == 0 ||
1853                strcmp (s, "r1") == 0 ||
1854                strcmp (s, "r2") == 0 ||
1855                strcmp (s, "r3") == 0 ||
1856                strcmp (s, "r4") == 0 ||
1857                strcmp (s, "r5") == 0 ||
1858                strcmp (s, "r6") == 0 ||
1859                strcmp (s, "r7") == 0)
1860         {
1861           char buffer[10];
1862           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1863           emitcode ("push", buffer);
1864         }
1865       else
1866         {
1867           emitcode ("push", s);
1868         }
1869
1870       break;
1871
1872     case AOP_CRY:
1873       // destination is carry for return-use-only
1874       d = (IS_OP_RUONLY (result)) ? "c" : aop->aopu.aop_dir;
1875       
1876       // source is no literal and not in carry
1877       if ((s != zero) && (s != one) && strcmp (s, "c"))
1878         {
1879           MOVA (s);
1880           /* set C, if a >= 1 */
1881           emitcode ("add", "a,#!constbyte",0xff);
1882           s = "c";
1883         }
1884       // now source is zero, one or carry
1885
1886       /* if result no bit variable */
1887       if (!d)
1888         {
1889           if (!strcmp (s, "c"))
1890             {
1891               /* inefficient: move carry into A and use jz/jnz */
1892               emitcode ("clr", "a");
1893               emitcode ("rlc", "a");
1894               accuse = TRUE;
1895             }
1896           else
1897             {
1898               MOVA (s);
1899               accuse = TRUE;
1900             }
1901         }
1902       else if (s == zero)
1903           emitcode ("clr", "%s", d);
1904       else if (s == one)
1905           emitcode ("setb", "%s", d);
1906       else if (strcmp (s, d))
1907           emitcode ("mov", "%s,c", d);
1908       break;
1909
1910     case AOP_STR:
1911       aop->coff = offset;
1912       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1913         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1914       break;
1915
1916     case AOP_ACC:
1917       accuse = TRUE;
1918       aop->coff = offset;
1919       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1920         break;
1921
1922       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1923         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1924       break;
1925
1926     default:
1927       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1928               "aopPut got unsupported aop->type");
1929       exit (1);
1930     }
1931
1932     return accuse;
1933 }
1934
1935
1936 /*--------------------------------------------------------------------*/
1937 /* reAdjustPreg - points a register back to where it should (coff==0) */
1938 /*--------------------------------------------------------------------*/
1939 static void
1940 reAdjustPreg (asmop * aop)
1941 {
1942   if ((aop->coff==0) || (aop->size <= 1))
1943     return;
1944
1945   switch (aop->type)
1946     {
1947     case AOP_R0:
1948     case AOP_R1:
1949       while (aop->coff--)
1950         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1951       break;
1952     case AOP_DPTR:
1953     case AOP_DPTR2:
1954       if (aop->type == AOP_DPTR2)
1955         {
1956           genSetDPTR (1);
1957           _flushLazyDPS ();
1958         }
1959       while (aop->coff--)
1960         {
1961           emitcode ("lcall", "__decdptr");
1962         }
1963
1964       if (aop->type == AOP_DPTR2)
1965         {
1966           genSetDPTR (0);
1967         }
1968       break;
1969     }
1970   aop->coff = 0;
1971 }
1972
1973 /*-----------------------------------------------------------------*/
1974 /* opIsGptr: returns non-zero if the passed operand is             */
1975 /* a generic pointer type.                                         */
1976 /*-----------------------------------------------------------------*/
1977 static int
1978 opIsGptr (operand * op)
1979 {
1980   if (op && IS_GENPTR (operandType (op)) && (AOP_SIZE (op) == GPTRSIZE))
1981     {
1982       return 1;
1983     }
1984   return 0;
1985 }
1986
1987 /*-----------------------------------------------------------------*/
1988 /* getDataSize - get the operand data size                         */
1989 /*-----------------------------------------------------------------*/
1990 static int
1991 getDataSize (operand * op)
1992 {
1993   int size = AOP_SIZE (op);
1994
1995   if (size == GPTRSIZE)
1996     {
1997       sym_link *type = operandType (op);
1998       if (IS_GENPTR (type))
1999         {
2000           /* generic pointer; arithmetic operations
2001            * should ignore the high byte (pointer type).
2002            */
2003           size--;
2004         }
2005     }
2006   return size;
2007 }
2008
2009 /*-----------------------------------------------------------------*/
2010 /* outAcc - output Acc                                             */
2011 /*-----------------------------------------------------------------*/
2012 static void
2013 outAcc (operand * result)
2014 {
2015   int size, offset;
2016   size = getDataSize (result);
2017   if (size)
2018     {
2019       aopPut (result, "a", 0);
2020       size--;
2021       offset = 1;
2022       /* unsigned or positive */
2023       while (size--)
2024         {
2025           aopPut (result, zero, offset++);
2026         }
2027     }
2028 }
2029
2030 /*-----------------------------------------------------------------*/
2031 /* outBitC - output a bit C                                        */
2032 /*-----------------------------------------------------------------*/
2033 static void
2034 outBitC (operand * result)
2035 {
2036   /* if the result is bit */
2037   if (AOP_TYPE (result) == AOP_CRY)
2038     {
2039       aopPut (result, "c", 0);
2040     }
2041   else
2042     {
2043       emitcode ("clr", "a");
2044       emitcode ("rlc", "a");
2045       outAcc (result);
2046     }
2047 }
2048
2049 /*-----------------------------------------------------------------*/
2050 /* toBoolean - emit code for orl a,operator(sizeop)                */
2051 /*-----------------------------------------------------------------*/
2052 static void
2053 toBoolean (operand * oper)
2054 {
2055   int  size = AOP_SIZE (oper) - 1;
2056   int  offset = 1;
2057   bool pushedB;
2058
2059   /* The generic part of a generic pointer should
2060    * not participate in it's truth value.
2061    *
2062    * i.e. 0x10000000 is zero.
2063    */
2064   if (opIsGptr (oper))
2065     {
2066       D (emitcode (";", "toBoolean: generic ptr special case."));
2067       size--;
2068     }
2069
2070   _startLazyDPSEvaluation ();
2071   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2072   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2073     {
2074       pushedB = pushB ();
2075       emitcode("mov", "b,a");
2076       while (--size)
2077         {
2078           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2079           emitcode ("orl", "b,a");
2080         }
2081       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2082       emitcode ("orl", "a,b");
2083       popB (pushedB);
2084     }
2085   else
2086     {
2087       while (size--)
2088         {
2089           emitcode ("orl", "a,%s",
2090                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2091         }
2092     }
2093   _endLazyDPSEvaluation ();
2094 }
2095
2096
2097 /*-----------------------------------------------------------------*/
2098 /* genNot - generate code for ! operation                          */
2099 /*-----------------------------------------------------------------*/
2100 static void
2101 genNot (iCode * ic)
2102 {
2103   symbol *tlbl;
2104
2105   D (emitcode (";", "genNot"));
2106
2107   /* assign asmOps to operand & result */
2108   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2109   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2110
2111   /* if in bit space then a special case */
2112   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2113     {
2114       /* if left==result then cpl bit */
2115       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2116         {
2117           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2118         }
2119       else
2120         {
2121           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2122           emitcode ("cpl", "c");
2123           outBitC (IC_RESULT (ic));
2124         }
2125       goto release;
2126     }
2127
2128   toBoolean (IC_LEFT (ic));
2129
2130   /* set C, if a == 0 */
2131   tlbl = newiTempLabel (NULL);
2132   emitcode ("cjne", "a,#0x01,!tlabel", tlbl->key + 100);
2133   emitLabel (tlbl);
2134   outBitC (IC_RESULT (ic));
2135
2136 release:
2137   /* release the aops */
2138   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2139   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2140 }
2141
2142
2143 /*-----------------------------------------------------------------*/
2144 /* genCpl - generate code for complement                           */
2145 /*-----------------------------------------------------------------*/
2146 static void
2147 genCpl (iCode * ic)
2148 {
2149   int offset = 0;
2150   int size;
2151   symbol *tlbl;
2152   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2153
2154   D(emitcode (";", "genCpl"));
2155
2156   /* assign asmOps to operand & result */
2157   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2158   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2159
2160   /* special case if in bit space */
2161   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2162     {
2163       char *l;
2164
2165       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2166           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2167         {
2168           /* promotion rules are responsible for this strange result:
2169              bit -> int -> ~int -> bit
2170              uchar -> int -> ~int -> bit
2171           */
2172           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2173           goto release;
2174         }
2175
2176       tlbl=newiTempLabel(NULL);
2177       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2178       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2179           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2180           IS_AOP_PREG (IC_LEFT (ic)))
2181         {
2182           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2183         }
2184       else
2185         {
2186           MOVA (l);
2187           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2188         }
2189       emitLabel (tlbl);
2190       outBitC (IC_RESULT(ic));
2191       goto release;
2192     }
2193
2194   size = AOP_SIZE (IC_RESULT (ic));
2195   _startLazyDPSEvaluation ();
2196   while (size--)
2197     {
2198       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2199       MOVA (l);
2200       emitcode ("cpl", "a");
2201       aopPut (IC_RESULT (ic), "a", offset++);
2202     }
2203   _endLazyDPSEvaluation ();
2204
2205
2206 release:
2207   /* release the aops */
2208   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2209   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2210 }
2211
2212 /*-----------------------------------------------------------------*/
2213 /* genUminusFloat - unary minus for floating points                */
2214 /*-----------------------------------------------------------------*/
2215 static void
2216 genUminusFloat (operand * op, operand * result)
2217 {
2218   int size, offset = 0;
2219   char *l;
2220
2221   D (emitcode (";", "genUminusFloat"));
2222
2223   /* for this we just copy and then flip the bit */
2224
2225   _startLazyDPSEvaluation ();
2226   size = AOP_SIZE (op) - 1;
2227
2228   while (size--)
2229     {
2230       aopPut (result,
2231               aopGet (op, offset, FALSE, FALSE, NULL),
2232               offset);
2233       offset++;
2234     }
2235
2236   l = aopGet (op, offset, FALSE, FALSE, NULL);
2237   MOVA (l);
2238
2239   emitcode ("cpl", "acc.7");
2240   aopPut (result, "a", offset);
2241   _endLazyDPSEvaluation ();
2242 }
2243
2244 /*-----------------------------------------------------------------*/
2245 /* genUminus - unary minus code generation                         */
2246 /*-----------------------------------------------------------------*/
2247 static void
2248 genUminus (iCode * ic)
2249 {
2250   int offset, size;
2251   sym_link *optype;
2252
2253   D (emitcode (";", "genUminus"));
2254
2255   /* assign asmops */
2256   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2257   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2258
2259   /* if both in bit space then special
2260      case */
2261   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2262       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2263     {
2264
2265       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2266       emitcode ("cpl", "c");
2267       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2268       goto release;
2269     }
2270
2271   optype = operandType (IC_LEFT (ic));
2272
2273   /* if float then do float stuff */
2274   if (IS_FLOAT (optype))
2275     {
2276       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2277       goto release;
2278     }
2279
2280   /* otherwise subtract from zero */
2281   size = AOP_SIZE (IC_LEFT (ic));
2282   offset = 0;
2283   _startLazyDPSEvaluation ();
2284   while (size--)
2285     {
2286       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2287       if (!strcmp (l, "a"))
2288         {
2289           if (offset == 0)
2290             SETC;
2291           emitcode ("cpl", "a");
2292           emitcode ("addc", "a,#0x00");
2293         }
2294       else
2295         {
2296           if (offset == 0)
2297             CLRC;
2298           emitcode ("clr", "a");
2299           emitcode ("subb", "a,%s", l);
2300         }
2301       aopPut (IC_RESULT (ic), "a", offset++);
2302     }
2303   _endLazyDPSEvaluation ();
2304
2305   /* if any remaining bytes in the result */
2306   /* we just need to propagate the sign   */
2307   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2308     {
2309       emitcode ("rlc", "a");
2310       emitcode ("subb", "a,acc");
2311       while (size--)
2312         aopPut (IC_RESULT (ic), "a", offset++);
2313     }
2314
2315 release:
2316   /* release the aops */
2317   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2318   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2319 }
2320
2321 /*-----------------------------------------------------------------*/
2322 /* savermask - saves registers in the mask                         */
2323 /*-----------------------------------------------------------------*/
2324 static void savermask(bitVect *rs_mask)
2325 {
2326   int i;
2327
2328   if (options.useXstack)
2329     {
2330       if (bitVectBitValue (rs_mask, R0_IDX))
2331           emitcode ("mov", "b,r0");
2332       emitcode ("mov", "r0,%s", spname);
2333       for (i = 0; i < ds390_nRegs; i++)
2334         {
2335           if (bitVectBitValue (rs_mask, i))
2336             {
2337               if (i == R0_IDX)
2338                   emitcode ("mov", "a,b");
2339               else
2340                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2341               emitcode ("movx", "@r0,a");
2342               emitcode ("inc", "r0");
2343             }
2344         }
2345       emitcode ("mov", "%s,r0", spname);
2346       if (bitVectBitValue (rs_mask, R0_IDX))
2347           emitcode ("mov", "r0,b");
2348     }
2349   else
2350     {
2351       bool bits_pushed = FALSE;
2352       for (i = 0; i < ds390_nRegs; i++)
2353         {
2354           if (bitVectBitValue (rs_mask, i))
2355             {
2356               bits_pushed = pushReg (i, bits_pushed);
2357             }
2358         }
2359     }
2360 }
2361
2362 /*-----------------------------------------------------------------*/
2363 /* saveRegisters - will look for a call and save the registers     */
2364 /*-----------------------------------------------------------------*/
2365 static void
2366 saveRegisters (iCode * lic)
2367 {
2368   iCode *ic;
2369   bitVect *rsave;
2370
2371   /* look for call */
2372   for (ic = lic; ic; ic = ic->next)
2373     if (ic->op == CALL || ic->op == PCALL)
2374       break;
2375
2376   if (!ic)
2377     {
2378       fprintf (stderr, "found parameter push with no function call\n");
2379       return;
2380     }
2381
2382   /* if the registers have been saved already or don't need to be then
2383      do nothing */
2384   if (ic->regsSaved
2385       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2386     return;
2387
2388   /* special case if DPTR alive across a function call then must save it
2389      even though callee saves */
2390   if (IS_SYMOP(IC_LEFT(ic)) &&
2391       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2392     {
2393       int i;
2394       rsave = newBitVect(ic->rMask->size);
2395       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2396           if (bitVectBitValue(ic->rMask,i))
2397               rsave = bitVectSetBit(rsave,i);
2398       }
2399       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2400     }
2401   else
2402     {
2403       /* save the registers in use at this time but skip the
2404          ones for the result */
2405       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2406                              ds390_rUmaskForOp (IC_RESULT(ic)));
2407     }
2408   ic->regsSaved = 1;
2409   savermask(rsave);
2410 }
2411
2412 /*-----------------------------------------------------------------*/
2413 /* usavermask - restore registers with mask                        */
2414 /*-----------------------------------------------------------------*/
2415 static void unsavermask(bitVect *rs_mask)
2416 {
2417   int i;
2418
2419   if (options.useXstack)
2420     {
2421       emitcode ("mov", "r0,%s", spname);
2422       for (i = ds390_nRegs; i >= 0; i--)
2423         {
2424           if (bitVectBitValue (rs_mask, i))
2425             {
2426               regs * reg = REG_WITH_INDEX (i);
2427               emitcode ("dec", "r0");
2428               emitcode ("movx", "a,@r0");
2429               if (i == R0_IDX)
2430                 {
2431                   emitcode ("push", "acc");
2432                 }
2433               else
2434                 {
2435                   emitcode ("mov", "%s,a", reg->name);
2436                 }
2437             }
2438         }
2439       emitcode ("mov", "%s,r0", spname);
2440       if (bitVectBitValue (rs_mask, R0_IDX))
2441         {
2442           emitcode ("pop", "ar0");
2443         }
2444     }
2445   else
2446     {
2447       bool bits_popped = FALSE;
2448       for (i = ds390_nRegs; i >= 0; i--)
2449         {
2450           if (bitVectBitValue (rs_mask, i))
2451             {
2452               bits_popped = popReg (i, bits_popped);
2453             }
2454         }
2455     }
2456 }
2457
2458 /*-----------------------------------------------------------------*/
2459 /* unsaveRegisters - pop the pushed registers                      */
2460 /*-----------------------------------------------------------------*/
2461 static void
2462 unsaveRegisters (iCode * ic)
2463 {
2464   bitVect *rsave;
2465
2466   if (IS_SYMOP(IC_LEFT (ic)) &&
2467       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2468       int i;
2469       rsave = newBitVect(ic->rMask->size);
2470       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2471           if (bitVectBitValue(ic->rMask,i))
2472               rsave = bitVectSetBit(rsave,i);
2473       }
2474       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2475   } else {
2476     /* restore the registers in use at this time but skip the
2477        ones for the result */
2478     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2479                            ds390_rUmaskForOp (IC_RESULT(ic)));
2480   }
2481   unsavermask(rsave);
2482 }
2483
2484
2485 /*-----------------------------------------------------------------*/
2486 /* pushSide -                                                      */
2487 /*-----------------------------------------------------------------*/
2488 static void
2489 pushSide (operand * oper, int size, iCode * ic)
2490 {
2491   int offset = 0;
2492   int nPushed = _G.r0Pushed + _G.r1Pushed;
2493
2494   aopOp (oper, ic, FALSE, FALSE);
2495
2496   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2497     {
2498       while (offset < size)
2499         {
2500           char *l = aopGet (oper, offset, FALSE, TRUE, NULL);
2501           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2502         }
2503       freeAsmop (oper, NULL, ic, TRUE);
2504       offset = 0;
2505       while (offset < size)
2506         {
2507           emitcode ("push", "%s", fReturn[offset++]);
2508         }
2509       return;
2510     }
2511
2512   _startLazyDPSEvaluation ();
2513   while (size--)
2514     {
2515       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2516       if (AOP_TYPE (oper) != AOP_REG &&
2517           AOP_TYPE (oper) != AOP_DIR &&
2518           strcmp (l, "a"))
2519         {
2520           MOVA (l);
2521           emitcode ("push", "acc");
2522         }
2523       else
2524         {
2525           emitcode ("push", "%s", l);
2526         }
2527     }
2528   _endLazyDPSEvaluation ();
2529   freeAsmop (oper, NULL, ic, TRUE);
2530 }
2531
2532 /*-----------------------------------------------------------------*/
2533 /* assignResultValue - also indicates if acc is in use afterwards  */
2534 /*-----------------------------------------------------------------*/
2535 static bool
2536 assignResultValue (operand * oper, operand * func)
2537 {
2538   int offset = 0;
2539   unsigned size = AOP_SIZE (oper);
2540   bool accuse = FALSE;
2541   bool pushedA = FALSE;
2542
2543   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2544     {
2545       outBitC (oper);
2546       return FALSE;
2547     }
2548
2549   if (size == fReturnSizeDS390)
2550   {
2551       /* I don't think this case can ever happen... */
2552       /* ACC is the last part of this. If writing the result
2553        * uses ACC, we must preserve it.
2554        */
2555       if (AOP_NEEDSACC(oper))
2556       {
2557           emitcode(";", "assignResultValue special case for ACC.");
2558           emitcode("push", "acc");
2559           pushedA = TRUE;
2560           size--;
2561       }
2562   }
2563
2564   _startLazyDPSEvaluation ();
2565   while (size--)
2566     {
2567       accuse |= aopPut (oper, fReturn[offset], offset);
2568       offset++;
2569     }
2570   _endLazyDPSEvaluation ();
2571
2572   if (pushedA)
2573     {
2574         emitcode ("pop", "acc");
2575         accuse |= aopPut (oper, "a", offset);
2576     }
2577   return accuse;
2578 }
2579
2580
2581 /*-----------------------------------------------------------------*/
2582 /* genXpush - pushes onto the external stack                       */
2583 /*-----------------------------------------------------------------*/
2584 static void
2585 genXpush (iCode * ic)
2586 {
2587   asmop *aop = newAsmop (0);
2588   regs *r;
2589   int size, offset = 0;
2590
2591   D (emitcode (";", "genXpush"));
2592
2593   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2594   r = getFreePtr (ic, &aop, FALSE);
2595
2596   size = AOP_SIZE (IC_LEFT (ic));
2597
2598   if (size == 1)
2599     {
2600       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2601       emitcode ("mov", "%s,_spx", r->name);
2602       emitcode ("inc", "_spx"); // allocate space first
2603       emitcode ("movx", "@%s,a", r->name);
2604     }
2605   else
2606     {
2607       // allocate space first
2608       emitcode ("mov", "%s,_spx", r->name);
2609       MOVA (r->name);
2610       emitcode ("add", "a,#%d", size);
2611       emitcode ("mov", "_spx,a");
2612
2613       _startLazyDPSEvaluation ();
2614       while (size--)
2615         {
2616           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2617           emitcode ("movx", "@%s,a", r->name);
2618           emitcode ("inc", "%s", r->name);
2619         }
2620       _endLazyDPSEvaluation ();
2621     }
2622
2623   freeAsmop (NULL, aop, ic, TRUE);
2624   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2625 }
2626
2627 /*-----------------------------------------------------------------*/
2628 /* genIpush - generate code for pushing this gets a little complex */
2629 /*-----------------------------------------------------------------*/
2630 static void
2631 genIpush (iCode * ic)
2632 {
2633   int size, offset = 0;
2634   char *l;
2635   char *prev = "";
2636
2637   D (emitcode (";", "genIpush"));
2638
2639   /* if this is not a parm push : ie. it is spill push
2640      and spill push is always done on the local stack */
2641   if (!ic->parmPush)
2642     {
2643
2644       /* and the item is spilt then do nothing */
2645       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2646         return;
2647
2648       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2649       size = AOP_SIZE (IC_LEFT (ic));
2650       /* push it on the stack */
2651       _startLazyDPSEvaluation ();
2652       while (size--)
2653         {
2654           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2655           if (*l == '#')
2656             {
2657               MOVA (l);
2658               l = "acc";
2659             }
2660           emitcode ("push", "%s", l);
2661         }
2662       _endLazyDPSEvaluation ();
2663       return;
2664     }
2665
2666   /* this is a parameter push: in this case we call
2667      the routine to find the call and save those
2668      registers that need to be saved */
2669   saveRegisters (ic);
2670
2671   /* if use external stack then call the external
2672      stack pushing routine */
2673   if (options.useXstack)
2674     {
2675       genXpush (ic);
2676       return;
2677     }
2678
2679   /* then do the push */
2680   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2681
2682   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2683   size = AOP_SIZE (IC_LEFT (ic));
2684
2685   _startLazyDPSEvaluation ();
2686   while (size--)
2687     {
2688       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2689       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2690           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2691           strcmp (l, "acc"))
2692         {
2693           if (strcmp (l, prev) || *l == '@')
2694             MOVA (l);
2695           emitcode ("push", "acc");
2696         }
2697       else
2698         {
2699           emitcode ("push", "%s", l);
2700         }
2701       prev = l;
2702     }
2703   _endLazyDPSEvaluation ();
2704
2705   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2706 }
2707
2708 /*-----------------------------------------------------------------*/
2709 /* genIpop - recover the registers: can happen only for spilling   */
2710 /*-----------------------------------------------------------------*/
2711 static void
2712 genIpop (iCode * ic)
2713 {
2714   int size, offset;
2715
2716   D (emitcode (";", "genIpop"));
2717
2718   /* if the temp was not pushed then */
2719   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2720     return;
2721
2722   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2723   size = AOP_SIZE (IC_LEFT (ic));
2724   offset = (size - 1);
2725   _startLazyDPSEvaluation ();
2726   while (size--)
2727     {
2728       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2729                                      FALSE, TRUE, NULL));
2730     }
2731   _endLazyDPSEvaluation ();
2732
2733   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2734 }
2735
2736 /*-----------------------------------------------------------------*/
2737 /* popForBranch - recover the spilt registers for a branch         */
2738 /*-----------------------------------------------------------------*/
2739 static void
2740 popForBranch (iCode * ic, bool markGenerated)
2741 {
2742   while (ic && ic->op == IPOP)
2743     {
2744       genIpop (ic);
2745       if (markGenerated)
2746         ic->generated = 1;    /* mark the icode as generated */
2747       ic = ic->next;
2748     }
2749 }
2750
2751 /*-----------------------------------------------------------------*/
2752 /* saveRBank - saves an entire register bank on the stack          */
2753 /*-----------------------------------------------------------------*/
2754 static void
2755 saveRBank (int bank, iCode * ic, bool pushPsw)
2756 {
2757   int i;
2758   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2759   asmop *aop = NULL;
2760   regs *r = NULL;
2761
2762   if (options.useXstack)
2763     {
2764       if (!ic)
2765         {
2766           /* Assume r0 is available for use. */
2767           r = REG_WITH_INDEX (R0_IDX);
2768         }
2769       else
2770         {
2771           aop = newAsmop (0);
2772           r = getFreePtr (ic, &aop, FALSE);
2773         }
2774       // allocate space first
2775       emitcode ("mov", "%s,_spx", r->name);
2776       MOVA (r->name);
2777       emitcode ("add", "a,#%d", count);
2778       emitcode ("mov", "_spx,a");
2779     }
2780
2781   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2782     {
2783       if (options.useXstack)
2784         {
2785           emitcode ("mov", "a,(%s+%d)",
2786                     regs390[i].base, 8 * bank + regs390[i].offset);
2787           emitcode ("movx", "@%s,a", r->name);
2788           if (--count)
2789             emitcode ("inc", "%s", r->name);
2790         }
2791       else
2792         emitcode ("push", "(%s+%d)",
2793                   regs390[i].base, 8 * bank + regs390[i].offset);
2794     }
2795
2796   if (ds390_nBitRegs > 0)
2797     {
2798       if (options.useXstack)
2799         {
2800           emitcode ("mov", "a,bits");
2801           emitcode ("movx", "@%s,a", r->name);
2802           if (--count)
2803             emitcode ("inc", "%s", r->name);
2804         }
2805       else
2806         {
2807           emitcode ("push", "bits");
2808         }
2809       BitBankUsed = 1;
2810     }
2811
2812   if (pushPsw)
2813     {
2814       if (options.useXstack)
2815         {
2816           emitcode ("mov", "a,psw");
2817           emitcode ("movx", "@%s,a", r->name);
2818         }
2819       else
2820       {
2821         emitcode ("push", "psw");
2822       }
2823
2824       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2825     }
2826
2827   if (aop)
2828     {
2829       freeAsmop (NULL, aop, ic, TRUE);
2830     }
2831
2832   if (ic)
2833     {
2834       ic->bankSaved = 1;
2835     }
2836 }
2837
2838 /*-----------------------------------------------------------------*/
2839 /* unsaveRBank - restores the register bank from stack             */
2840 /*-----------------------------------------------------------------*/
2841 static void
2842 unsaveRBank (int bank, iCode * ic, bool popPsw)
2843 {
2844   int i;
2845   asmop *aop = NULL;
2846   regs *r = NULL;
2847
2848   if (options.useXstack)
2849     {
2850       if (!ic)
2851         {
2852           /* Assume r0 is available for use. */
2853           r = REG_WITH_INDEX (R0_IDX);
2854         }
2855       else
2856         {
2857           aop = newAsmop (0);
2858           r = getFreePtr (ic, &aop, FALSE);
2859         }
2860       emitcode ("mov", "%s,_spx", r->name);
2861     }
2862
2863   if (popPsw)
2864     {
2865       if (options.useXstack)
2866         {
2867           emitcode ("dec", "%s", r->name);
2868           emitcode ("movx", "a,@%s", r->name);
2869           emitcode ("mov", "psw,a");
2870         }
2871       else
2872       {
2873         emitcode ("pop", "psw");
2874       }
2875     }
2876
2877   if (ds390_nBitRegs > 0)
2878     {
2879       if (options.useXstack)
2880         {
2881           emitcode ("dec", "%s", r->name);
2882           emitcode ("movx", "a,@%s", r->name);
2883           emitcode ("mov", "bits,a");
2884         }
2885       else
2886         {
2887           emitcode ("pop", "bits");
2888         }
2889     }
2890
2891   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2892     {
2893       if (options.useXstack)
2894         {
2895           emitcode ("dec", "%s", r->name);
2896           emitcode ("movx", "a,@%s", r->name);
2897           emitcode ("mov", "(%s+%d),a",
2898                     regs390[i].base, 8 * bank + regs390[i].offset);
2899         }
2900       else
2901         {
2902           emitcode ("pop", "(%s+%d)",
2903                     regs390[i].base, 8 * bank + regs390[i].offset);
2904         }
2905     }
2906
2907   if (options.useXstack)
2908     {
2909       emitcode ("mov", "_spx,%s", r->name);
2910     }
2911
2912   if (aop)
2913     {
2914       freeAsmop (NULL, aop, ic, TRUE);
2915     }
2916 }
2917
2918 /*-----------------------------------------------------------------*/
2919 /* genSend - gen code for SEND                                     */
2920 /*-----------------------------------------------------------------*/
2921 static void genSend(set *sendSet)
2922 {
2923   iCode *sic;
2924   int bit_count = 0;
2925   int sendCount = 0 ;
2926   static int rb1_count = 0;
2927
2928   /* first we do all bit parameters */
2929   for (sic = setFirstItem (sendSet); sic;
2930        sic = setNextItem (sendSet))
2931     {
2932       if (sic->argreg > 12)
2933         {
2934           int bit = sic->argreg-13;
2935
2936           aopOp (IC_LEFT (sic), sic, FALSE,
2937                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2938
2939           /* if left is a literal then
2940              we know what the value is */
2941           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2942             {
2943               if (((int) operandLitValue (IC_LEFT (sic))))
2944                   emitcode ("setb", "b[%d]", bit);
2945               else
2946                   emitcode ("clr", "b[%d]", bit);
2947             }
2948           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2949             {
2950               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2951                 if (strcmp (l, "c"))
2952                     emitcode ("mov", "c,%s", l);
2953                 emitcode ("mov", "b[%d],c", bit);
2954             }
2955           else
2956             {
2957               /* we need to or */
2958               toBoolean (IC_LEFT (sic));
2959               /* set C, if a >= 1 */
2960               emitcode ("add", "a,#0xff");
2961               emitcode ("mov", "b[%d],c", bit);
2962             }
2963           bit_count++;
2964           BitBankUsed = 1;
2965
2966           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2967         }
2968     }
2969
2970   if (bit_count)
2971     {
2972       saveRegisters (setFirstItem (sendSet));
2973       emitcode ("mov", "bits,b");
2974     }
2975
2976   /* then we do all other parameters */
2977   for (sic = setFirstItem (sendSet); sic;
2978        sic = setNextItem (sendSet))
2979     {
2980       if (sic->argreg <= 12)
2981         {
2982           int size, offset = 0;
2983
2984           size = getSize (operandType (IC_LEFT (sic)));
2985           D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2986           if (sendCount == 0)
2987             { /* first parameter */
2988               // we know that dpl(hxb) is the result, so
2989               rb1_count = 0 ;
2990               _startLazyDPSEvaluation ();
2991               if (size>1)
2992                 {
2993                   aopOp (IC_LEFT (sic), sic, FALSE,
2994                          (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2995                 }
2996               else
2997                 {
2998                   aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2999                 }
3000               while (size--)
3001                 {
3002                   char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
3003                   if (strcmp (l, fReturn[offset]))
3004                     {
3005                       emitcode ("mov", "%s,%s", fReturn[offset], l);
3006                     }
3007                   offset++;
3008                 }
3009               _endLazyDPSEvaluation ();
3010               freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
3011               rb1_count =0;
3012             }
3013           else
3014             { /* if more parameter in registers */
3015               aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
3016               while (size--)
3017                 {
3018                   emitcode ("mov","b1_%d,%s",rb1_count++,
3019                             aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL));
3020                   offset++;
3021                 }
3022               freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
3023             }
3024           sendCount++;
3025         }
3026     }
3027 }
3028
3029 static void
3030 adjustEsp(const char *reg)
3031 {
3032     emitcode ("anl","%s,#3", reg);
3033     if (TARGET_IS_DS400)
3034     {
3035         emitcode ("orl","%s,#!constbyte",
3036                   reg,
3037                   (options.stack_loc >> 8) & 0xff);
3038     }
3039 }
3040
3041 /*-----------------------------------------------------------------*/
3042 /* selectRegBank - emit code to select the register bank           */
3043 /*-----------------------------------------------------------------*/
3044 static void
3045 selectRegBank (short bank, bool keepFlags)
3046 {
3047   /* if f.e. result is in carry */
3048   if (keepFlags)
3049     {
3050       emitcode ("anl", "psw,#0xE7");
3051       if (bank)
3052         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3053     }
3054   else
3055     {
3056       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3057     }
3058 }
3059
3060 /*-----------------------------------------------------------------*/
3061 /* genCall - generates a call statement                            */
3062 /*-----------------------------------------------------------------*/
3063 static void
3064 genCall (iCode * ic)
3065 {
3066   sym_link *dtype;
3067   sym_link *etype;
3068   bool restoreBank = FALSE;
3069   bool swapBanks = FALSE;
3070   bool accuse = FALSE;
3071   bool accPushed = FALSE;
3072   bool resultInF0 = FALSE;
3073   bool assignResultGenerated = FALSE;
3074
3075   D (emitcode (";", "genCall"));
3076
3077   /* if we are calling a not _naked function that is not using
3078      the same register bank then we need to save the
3079      destination registers on the stack */
3080   dtype = operandType (IC_LEFT (ic));
3081   etype = getSpec(dtype);
3082   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3083       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3084       IFFUNC_ISISR (currFunc->type))
3085   {
3086       if (!ic->bankSaved)
3087       {
3088            /* This is unexpected; the bank should have been saved in
3089             * genFunction.
3090             */
3091            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3092            restoreBank = TRUE;
3093       }
3094       swapBanks = TRUE;
3095   }
3096
3097   /* if caller saves & we have not saved then */
3098   if (!ic->regsSaved)
3099       saveRegisters (ic);
3100
3101   /* if send set is not empty then assign */
3102   /* We've saved all the registers we care about;
3103   * therefore, we may clobber any register not used
3104   * in the calling convention (i.e. anything not in
3105   * fReturn.
3106   */
3107   if (_G.sendSet)
3108     {
3109         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3110             genSend(reverseSet(_G.sendSet));
3111         } else {
3112             genSend(_G.sendSet);
3113         }
3114       _G.sendSet = NULL;
3115     }
3116
3117   if (swapBanks)
3118     {
3119       emitcode ("mov", "psw,#!constbyte",
3120          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3121     }
3122
3123   /* make the call */
3124   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3125                             OP_SYMBOL (IC_LEFT (ic))->rname :
3126                             OP_SYMBOL (IC_LEFT (ic))->name));
3127
3128   if (swapBanks)
3129     {
3130       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3131     }
3132
3133   /* if we need assign a result value */
3134   if ((IS_ITEMP (IC_RESULT (ic)) &&
3135        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3136        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3137         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3138         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3139       IS_TRUE_SYMOP (IC_RESULT (ic)))
3140     {
3141       if (isOperandInFarSpace (IC_RESULT (ic))
3142           && getSize (operandType (IC_RESULT (ic))) <= 2)
3143         {
3144           int size = getSize (operandType (IC_RESULT (ic)));
3145           bool pushedB = FALSE;
3146
3147           /* Special case for 1 or 2 byte return in far space. */
3148           MOVA (fReturn[0]);
3149           if (size > 1)
3150             {
3151               pushedB = pushB ();
3152               emitcode ("mov", "b,%s", fReturn[1]);
3153             }
3154
3155           _G.accInUse++;
3156           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3157           _G.accInUse--;
3158
3159           popB (pushedB);
3160
3161           aopPut (IC_RESULT (ic), "a", 0);
3162
3163           if (size > 1)
3164             {
3165               aopPut (IC_RESULT (ic), "b", 1);
3166             }
3167           assignResultGenerated = TRUE;
3168           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3169         }
3170       else
3171         {
3172           bool pushedB = pushB ();
3173           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3174           popB (pushedB);
3175
3176           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3177           assignResultGenerated = TRUE;
3178           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3179         }
3180     }
3181
3182   /* adjust the stack for parameters if required */
3183   if (ic->parmBytes)
3184     {
3185       int i;
3186       if (options.stack10bit) {
3187           if (ic->parmBytes <= 10) {
3188               emitcode(";","stack adjustment for parms");
3189               for (i=0; i < ic->parmBytes ; i++) {
3190                   emitcode("pop","acc");
3191               }
3192           } else {
3193               PROTECT_SP;
3194               emitcode ("clr","c");
3195               emitcode ("mov","a,sp");
3196               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3197               emitcode ("mov","sp,a");
3198               emitcode ("mov","a,esp");
3199               adjustEsp("a");
3200               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3201               emitcode ("mov","esp,a");
3202               UNPROTECT_SP;
3203           }
3204       } else {
3205           if (ic->parmBytes > 3)
3206             {
3207               if (accuse)
3208                 {
3209                   emitcode ("push", "acc");
3210                   accPushed = TRUE;
3211                 }
3212               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3213                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3214                   !assignResultGenerated)
3215                 {
3216                   emitcode ("mov", "F0,c");
3217                   resultInF0 = TRUE;
3218                 }
3219
3220               emitcode ("mov", "a,%s", spname);
3221               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3222               emitcode ("mov", "%s,a", spname);
3223
3224               /* unsaveRegisters from xstack needs acc, but */
3225               /* unsaveRegisters from stack needs this popped */
3226               if (accPushed && !options.useXstack)
3227                 {
3228                   emitcode ("pop", "acc");
3229                   accPushed = FALSE;
3230                 }
3231             }
3232           else
3233               for (i = 0; i < ic->parmBytes; i++)
3234                   emitcode ("dec", "%s", spname);
3235       }
3236   }
3237
3238   /* if we had saved some registers then unsave them */
3239   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3240     {
3241       if (accuse && !accPushed && options.useXstack)
3242         {
3243           /* xstack needs acc, but doesn't touch normal stack */
3244           emitcode ("push", "acc");
3245           accPushed = TRUE;
3246         }
3247       unsaveRegisters (ic);
3248     }
3249
3250   /* if register bank was saved then pop them */
3251   if (restoreBank)
3252     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3253
3254   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3255     {
3256       if (resultInF0)
3257           emitcode ("mov", "c,F0");
3258
3259       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3260       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3261       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3262     }
3263
3264   if (accPushed)
3265     emitcode ("pop", "acc");
3266 }
3267
3268 /*-----------------------------------------------------------------*/
3269 /* genPcall - generates a call by pointer statement                */
3270 /*-----------------------------------------------------------------*/
3271 static void
3272 genPcall (iCode * ic)
3273 {
3274   sym_link *dtype;
3275   sym_link *etype;
3276   symbol *rlbl = newiTempLabel (NULL);
3277   bool restoreBank=FALSE;
3278   bool resultInF0 = FALSE;
3279
3280   D (emitcode (";", "genPcall"));
3281
3282   dtype = operandType (IC_LEFT (ic))->next;
3283   etype = getSpec(dtype);
3284   /* if caller saves & we have not saved then */
3285   if (!ic->regsSaved)
3286     saveRegisters (ic);
3287
3288   /* if we are calling a not _naked function that is not using
3289      the same register bank then we need to save the
3290      destination registers on the stack */
3291   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3292       IFFUNC_ISISR (currFunc->type) &&
3293       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3294     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3295     restoreBank=TRUE;
3296   }
3297
3298   /* push the return address on to the stack */
3299   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3300   emitcode ("push", "acc");
3301   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3302   emitcode ("push", "acc");
3303
3304   if (options.model == MODEL_FLAT24)
3305     {
3306       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3307       emitcode ("push", "acc");
3308     }
3309
3310   /* now push the function address */
3311   pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3312
3313   /* if send set is not empty then assign */
3314   if (_G.sendSet)
3315     {
3316         genSend(reverseSet(_G.sendSet));
3317         _G.sendSet = NULL;
3318     }
3319
3320   /* make the call */
3321   emitcode ("ret", "");
3322   emitLabel (rlbl);
3323
3324
3325   /* if we need assign a result value */
3326   if ((IS_ITEMP (IC_RESULT (ic)) &&
3327        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3328        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3329         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3330       IS_TRUE_SYMOP (IC_RESULT (ic)))
3331     {
3332
3333       _G.accInUse++;
3334       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3335       _G.accInUse--;
3336
3337       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3338
3339       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3340     }
3341
3342   /* adjust the stack for parameters if required */
3343   if (ic->parmBytes)
3344     {
3345       int i;
3346       if (options.stack10bit) {
3347           if (ic->parmBytes <= 10) {
3348               emitcode(";","stack adjustment for parms");
3349               for (i=0; i < ic->parmBytes ; i++) {
3350                   emitcode("pop","acc");
3351               }
3352           } else {
3353               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3354                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3355                 {
3356                   emitcode ("mov", "F0,c");
3357                   resultInF0 = TRUE;
3358                 }
3359
3360               PROTECT_SP;
3361               emitcode ("clr","c");
3362               emitcode ("mov","a,sp");
3363               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3364               emitcode ("mov","sp,a");
3365               emitcode ("mov","a,esp");
3366               adjustEsp("a");
3367               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3368               emitcode ("mov","esp,a");
3369               UNPROTECT_SP;
3370           }
3371       } else {
3372           if (ic->parmBytes > 3) {
3373               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3374                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3375                 {
3376                   emitcode ("mov", "F0,c");
3377                   resultInF0 = TRUE;
3378                 }
3379
3380               emitcode ("mov", "a,%s", spname);
3381               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3382               emitcode ("mov", "%s,a", spname);
3383           }
3384           else
3385               for (i = 0; i < ic->parmBytes; i++)
3386                   emitcode ("dec", "%s", spname);
3387       }
3388     }
3389   /* if register bank was saved then unsave them */
3390   if (restoreBank)
3391     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3392
3393   /* if we had saved some registers then unsave them */
3394   if (ic->regsSaved)
3395     unsaveRegisters (ic);
3396
3397   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3398     {
3399       if (resultInF0)
3400           emitcode ("mov", "c,F0");
3401
3402       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3403       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3404       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3405     }
3406 }
3407
3408 /*-----------------------------------------------------------------*/
3409 /* resultRemat - result  is rematerializable                       */
3410 /*-----------------------------------------------------------------*/
3411 static int
3412 resultRemat (iCode * ic)
3413 {
3414   if (SKIP_IC (ic) || ic->op == IFX)
3415     return 0;
3416
3417   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3418     {
3419       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3420       if (sym->remat && !POINTER_SET (ic))
3421         return 1;
3422     }
3423
3424   return 0;
3425 }
3426
3427 /*-----------------------------------------------------------------*/
3428 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3429 /*-----------------------------------------------------------------*/
3430 static int
3431 regsCmp(void *p1, void *p2)
3432 {
3433   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3434 }
3435
3436 static bool
3437 inExcludeList (char *s)
3438 {
3439   const char *p = setFirstItem(options.excludeRegsSet);
3440
3441   if (p == NULL || STRCASECMP(p, "none") == 0)
3442     return FALSE;
3443
3444
3445   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3446 }
3447
3448 /*-----------------------------------------------------------------*/
3449 /* genFunction - generated code for function entry                 */
3450 /*-----------------------------------------------------------------*/
3451 static void
3452 genFunction (iCode * ic)
3453 {
3454   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3455   sym_link *ftype;
3456   bool     switchedPSW = FALSE;
3457   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3458
3459   D (emitcode (";", "genFunction"));
3460
3461   _G.nRegsSaved = 0;
3462   /* create the function header */
3463   emitcode (";", "-----------------------------------------");
3464   emitcode (";", " function %s", sym->name);
3465   emitcode (";", "-----------------------------------------");
3466
3467   emitcode ("", "%s:", sym->rname);
3468   lineCurr->isLabel = 1;
3469   ftype = operandType (IC_LEFT (ic));
3470   _G.currentFunc = sym;
3471
3472   if (IFFUNC_ISNAKED(ftype))
3473   {
3474       emitcode(";", "naked function: no prologue.");
3475       return;
3476   }
3477
3478   if (options.stack_probe)
3479       emitcode ("lcall","__stack_probe");
3480
3481   /* here we need to generate the equates for the
3482      register bank if required */
3483   if (FUNC_REGBANK (ftype) != rbank)
3484     {
3485       int i;
3486
3487       rbank = FUNC_REGBANK (ftype);
3488       for (i = 0; i < ds390_nRegs; i++)
3489         {
3490           if (regs390[i].print) {
3491               if (strcmp (regs390[i].base, "0") == 0)
3492                   emitcode ("", "%s !equ !constbyte",
3493                             regs390[i].dname,
3494                             8 * rbank + regs390[i].offset);
3495               else
3496                   emitcode ("", "%s !equ %s + !constbyte",
3497                             regs390[i].dname,
3498                             regs390[i].base,
3499                             8 * rbank + regs390[i].offset);
3500           }
3501         }
3502     }
3503
3504   /* if this is an interrupt service routine then
3505      save acc, b, dpl, dph  */
3506   if (IFFUNC_ISISR (sym->type))
3507     { /* is ISR */
3508       if (!inExcludeList ("acc"))
3509         emitcode ("push", "acc");
3510       if (!inExcludeList ("b"))
3511         emitcode ("push", "b");
3512       if (!inExcludeList ("dpl"))
3513         emitcode ("push", "dpl");
3514       if (!inExcludeList ("dph"))
3515         emitcode ("push", "dph");
3516       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3517         {
3518           emitcode ("push", "dpx");
3519           /* Make sure we're using standard DPTR */
3520           emitcode ("push", "dps");
3521           emitcode ("mov", "dps,#0");
3522           if (options.stack10bit)
3523             {
3524               /* This ISR could conceivably use DPTR2. Better save it. */
3525               emitcode ("push", "dpl1");
3526               emitcode ("push", "dph1");
3527               emitcode ("push", "dpx1");
3528               emitcode ("push",  DP2_RESULT_REG);
3529             }
3530         }
3531       /* if this isr has no bank i.e. is going to
3532          run with bank 0 , then we need to save more
3533          registers :-) */
3534       if (!FUNC_REGBANK (sym->type))
3535         {
3536           int i;
3537
3538           /* if this function does not call any other
3539              function then we can be economical and
3540              save only those registers that are used */
3541           if (!IFFUNC_HASFCALL(sym->type))
3542             {
3543               /* if any registers used */
3544               if (sym->regsUsed)
3545                 {
3546                   bool bits_pushed = FALSE;
3547                   /* save the registers used */
3548                   for (i = 0; i < sym->regsUsed->size; i++)
3549                     {
3550                       if (bitVectBitValue (sym->regsUsed, i))
3551                         bits_pushed = pushReg (i, bits_pushed);
3552                     }
3553                 }
3554             }
3555           else
3556             {
3557               /* this function has a function call. We cannot
3558                  determine register usage so we will have to push the
3559                  entire bank */
3560               saveRBank (0, ic, FALSE);
3561               if (options.parms_in_bank1)
3562                 {
3563                   for (i=0; i < 8 ; i++ )
3564                     {
3565                       emitcode ("push","%s",rb1regs[i]);
3566                     }
3567                 }
3568             }
3569         }
3570       else
3571         {
3572             /* This ISR uses a non-zero bank.
3573              *
3574              * We assume that the bank is available for our
3575              * exclusive use.
3576              *
3577              * However, if this ISR calls a function which uses some
3578              * other bank, we must save that bank entirely.
3579              */
3580             unsigned long banksToSave = 0;
3581
3582             if (IFFUNC_HASFCALL(sym->type))
3583             {
3584
3585 #define MAX_REGISTER_BANKS 4
3586
3587                 iCode *i;
3588                 int ix;
3589
3590                 for (i = ic; i; i = i->next)
3591                 {
3592                     if (i->op == ENDFUNCTION)
3593                     {
3594                         /* we got to the end OK. */
3595                         break;
3596                     }
3597
3598                     if (i->op == CALL)
3599                     {
3600                         sym_link *dtype;
3601
3602                         dtype = operandType (IC_LEFT(i));
3603                         if (dtype
3604                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3605                         {
3606                              /* Mark this bank for saving. */
3607                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3608                              {
3609                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3610                              }
3611                              else
3612                              {
3613                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3614                              }
3615
3616                              /* And note that we don't need to do it in
3617                               * genCall.
3618                               */
3619                              i->bankSaved = 1;
3620                         }
3621                     }
3622                     if (i->op == PCALL)
3623                     {
3624                         /* This is a mess; we have no idea what
3625                          * register bank the called function might
3626                          * use.
3627                          *
3628                          * The only thing I can think of to do is
3629                          * throw a warning and hope.
3630                          */
3631                         werror(W_FUNCPTR_IN_USING_ISR);
3632                     }
3633                 }
3634
3635                 if (banksToSave && options.useXstack)
3636                 {
3637                     /* Since we aren't passing it an ic,
3638                      * saveRBank will assume r0 is available to abuse.
3639                      *
3640                      * So switch to our (trashable) bank now, so
3641                      * the caller's R0 isn't trashed.
3642                      */
3643                     emitcode ("push", "psw");
3644                     emitcode ("mov", "psw,#!constbyte",
3645                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3646                     switchedPSW = TRUE;
3647                 }
3648
3649                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3650                 {
3651                      if (banksToSave & (1 << ix))
3652                      {
3653                          saveRBank(ix, NULL, FALSE);
3654                      }
3655                 }
3656             }
3657             // TODO: this needs a closer look
3658             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3659         }
3660     }
3661   else
3662     {
3663       /* if callee-save to be used for this function
3664          then save the registers being used in this function */
3665       if (IFFUNC_CALLEESAVES(sym->type))
3666         {
3667           int i;
3668
3669           /* if any registers used */
3670           if (sym->regsUsed)
3671             {
3672               bool bits_pushed = FALSE;
3673               /* save the registers used */
3674               for (i = 0; i < sym->regsUsed->size; i++)
3675                 {
3676                   if (bitVectBitValue (sym->regsUsed, i))
3677                     {
3678                       bits_pushed = pushReg (i, bits_pushed);
3679                       _G.nRegsSaved++;
3680                     }
3681                 }
3682             }
3683         }
3684     }
3685
3686   /* set the register bank to the desired value */
3687   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3688    && !switchedPSW)
3689     {
3690       emitcode ("push", "psw");
3691       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3692     }
3693
3694   if (fReentrant &&
3695        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3696       if (options.stack10bit) {
3697           emitcode ("push","_bpx");
3698           emitcode ("push","_bpx+1");
3699           emitcode ("mov","_bpx,%s",spname);
3700           emitcode ("mov","_bpx+1,esp");
3701           adjustEsp("_bpx+1");
3702       } else {
3703           if (options.useXstack)
3704           {
3705               emitcode ("mov", "r0,%s", spname);
3706               emitcode ("mov", "a,_bp");
3707               emitcode ("movx", "@r0,a");
3708               emitcode ("inc", "%s", spname);
3709           } else {
3710               /* set up the stack */
3711               emitcode ("push", "_bp"); /* save the callers stack  */
3712           }
3713           emitcode ("mov", "_bp,%s", spname);
3714       }
3715   }
3716
3717   /* adjust the stack for the function */
3718   if (sym->stack) {
3719       int i = sym->stack;
3720       if (options.stack10bit) {
3721           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3722           assert (sym->recvSize <= 4);
3723           if (sym->stack <= 8) {
3724               while (i--) emitcode ("push","acc");
3725           } else {
3726               PROTECT_SP;
3727               emitcode ("mov","a,sp");
3728               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3729               emitcode ("mov","sp,a");
3730               emitcode ("mov","a,esp");
3731               adjustEsp("a");
3732               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3733               emitcode ("mov","esp,a");
3734               UNPROTECT_SP;
3735           }
3736       } else {
3737           if (i > 256)
3738               werror (W_STACK_OVERFLOW, sym->name);
3739
3740           if (i > 3 && sym->recvSize < 4) {
3741
3742               emitcode ("mov", "a,sp");
3743               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3744               emitcode ("mov", "sp,a");
3745
3746           } else
3747               while (i--)
3748                   emitcode ("inc", "sp");
3749       }
3750   }
3751
3752   if (sym->xstack)
3753     {
3754
3755       emitcode ("mov", "a,_spx");
3756       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3757       emitcode ("mov", "_spx,a");
3758     }
3759
3760   /* if critical function then turn interrupts off */
3761   if (IFFUNC_ISCRITICAL (ftype))
3762     {
3763       symbol *tlbl = newiTempLabel (NULL);
3764       emitcode ("setb", "c");
3765       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3766       emitcode ("clr", "c");
3767       emitLabel (tlbl);
3768       emitcode ("push", "psw"); /* save old ea via c in psw */
3769     }
3770 }
3771
3772 /*-----------------------------------------------------------------*/
3773 /* genEndFunction - generates epilogue for functions               */
3774 /*-----------------------------------------------------------------*/
3775 static void
3776 genEndFunction (iCode * ic)
3777 {
3778   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3779   lineNode *lnp = lineCurr;
3780   bitVect  *regsUsed;
3781   bitVect  *regsUsedPrologue;
3782   bitVect  *regsUnneeded;
3783   int      idx;
3784
3785   D (emitcode (";", "genEndFunction"));
3786
3787   _G.currentFunc = NULL;
3788   if (IFFUNC_ISNAKED(sym->type))
3789   {
3790       emitcode(";", "naked function: no epilogue.");
3791       if (options.debug && currFunc)
3792         debugFile->writeEndFunction (currFunc, ic, 0);
3793       return;
3794   }
3795
3796   if (IFFUNC_ISCRITICAL (sym->type))
3797     {
3798       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3799         {
3800           emitcode ("rlc", "a");   /* save c in a */
3801           emitcode ("pop", "psw"); /* restore ea via c in psw */
3802           emitcode ("mov", "ea,c");
3803           emitcode ("rrc", "a");   /* restore c from a */
3804         }
3805       else
3806         {
3807           emitcode ("pop", "psw"); /* restore ea via c in psw */
3808           emitcode ("mov", "ea,c");
3809         }
3810     }
3811
3812   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3813        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3814
3815       if (options.stack10bit) {
3816           PROTECT_SP;
3817           emitcode ("mov", "sp,_bpx", spname);
3818           emitcode ("mov", "esp,_bpx+1", spname);
3819           UNPROTECT_SP;
3820       } else {
3821           emitcode ("mov", "%s,_bp", spname);
3822       }
3823   }
3824
3825   /* if use external stack but some variables were
3826      added to the local stack then decrement the
3827      local stack */
3828   if (options.useXstack && sym->stack) {
3829       emitcode ("mov", "a,sp");
3830       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3831       emitcode ("mov", "sp,a");
3832   }
3833
3834
3835   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3836        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3837
3838       if (options.useXstack) {
3839           emitcode ("mov", "r0,%s", spname);
3840           emitcode ("movx", "a,@r0");
3841           emitcode ("mov", "_bp,a");
3842           emitcode ("dec", "%s", spname);
3843       } else {
3844           if (options.stack10bit) {
3845               emitcode ("pop", "_bpx+1");
3846               emitcode ("pop", "_bpx");
3847           } else {
3848               emitcode ("pop", "_bp");
3849           }
3850       }
3851   }
3852
3853   /* restore the register bank  */
3854   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3855   {
3856     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3857      || !options.useXstack)
3858     {
3859         /* Special case of ISR using non-zero bank with useXstack
3860          * is handled below.
3861          */
3862         emitcode ("pop", "psw");
3863     }
3864   }
3865
3866   if (IFFUNC_ISISR (sym->type))
3867     { /* is ISR */
3868
3869       /* now we need to restore the registers */
3870       /* if this isr has no bank i.e. is going to
3871          run with bank 0 , then we need to save more
3872          registers :-) */
3873       if (!FUNC_REGBANK (sym->type))
3874         {
3875           int i;
3876           /* if this function does not call any other
3877              function then we can be economical and
3878              save only those registers that are used */
3879           if (!IFFUNC_HASFCALL(sym->type))
3880             {
3881               /* if any registers used */
3882               if (sym->regsUsed)
3883                 {
3884                   bool bits_popped = FALSE;
3885                   /* save the registers used */
3886                   for (i = sym->regsUsed->size; i >= 0; i--)
3887                     {
3888                       if (bitVectBitValue (sym->regsUsed, i))
3889                         bits_popped = popReg (i, bits_popped);
3890                     }
3891                 }
3892             }
3893           else
3894             {
3895               /* this function has a function call. We cannot
3896                  determine register usage so we will have to pop the
3897                  entire bank */
3898               if (options.parms_in_bank1)
3899                 {
3900                   for (i = 7 ; i >= 0 ; i-- )
3901                     {
3902                       emitcode ("pop","%s",rb1regs[i]);
3903                     }
3904                 }
3905               unsaveRBank (0, ic, FALSE);
3906             }
3907         }
3908       else
3909         {
3910             /* This ISR uses a non-zero bank.
3911              *
3912              * Restore any register banks saved by genFunction
3913              * in reverse order.
3914              */
3915             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3916             int ix;
3917
3918             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3919             {
3920                 if (savedBanks & (1 << ix))
3921                 {
3922                     unsaveRBank(ix, NULL, FALSE);
3923                 }
3924             }
3925
3926             if (options.useXstack)
3927             {
3928                 /* Restore bank AFTER calling unsaveRBank,
3929                  * since it can trash r0.
3930                  */
3931                 emitcode ("pop", "psw");
3932             }
3933         }
3934
3935       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3936         {
3937           if (options.stack10bit)
3938             {
3939               emitcode ("pop", DP2_RESULT_REG);
3940               emitcode ("pop", "dpx1");
3941               emitcode ("pop", "dph1");
3942               emitcode ("pop", "dpl1");
3943             }
3944           emitcode ("pop", "dps");
3945           emitcode ("pop", "dpx");
3946         }
3947       if (!inExcludeList ("dph"))
3948         emitcode ("pop", "dph");
3949       if (!inExcludeList ("dpl"))
3950         emitcode ("pop", "dpl");
3951       if (!inExcludeList ("b"))
3952         emitcode ("pop", "b");
3953       if (!inExcludeList ("acc"))
3954         emitcode ("pop", "acc");
3955
3956       /* if debug then send end of function */
3957       if (options.debug && currFunc)
3958         {
3959           debugFile->writeEndFunction (currFunc, ic, 1);
3960         }
3961
3962       emitcode ("reti", "");
3963     }
3964   else
3965     {
3966       if (IFFUNC_CALLEESAVES(sym->type))
3967         {
3968           int i;
3969
3970           /* if any registers used */
3971           if (sym->regsUsed)
3972             {
3973               /* save the registers used */
3974               for (i = sym->regsUsed->size; i >= 0; i--)
3975                 {
3976                   if (bitVectBitValue (sym->regsUsed, i))
3977                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3978                 }
3979             }
3980         }
3981
3982       /* if debug then send end of function */
3983       if (options.debug && currFunc)
3984         {
3985           debugFile->writeEndFunction (currFunc, ic, 1);
3986         }
3987
3988       emitcode ("ret", "");
3989     }
3990
3991   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3992     return;
3993
3994   /* If this was an interrupt handler using bank 0 that called another */
3995   /* function, then all registers must be saved; nothing to optimized. */
3996   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3997       && !FUNC_REGBANK(sym->type))
3998     return;
3999
4000   /* There are no push/pops to optimize if not callee-saves or ISR */
4001   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
4002     return;
4003
4004   /* If there were stack parameters, we cannot optimize without also    */
4005   /* fixing all of the stack offsets; this is too dificult to consider. */
4006   if (FUNC_HASSTACKPARM(sym->type))
4007     return;
4008
4009   /* Compute the registers actually used */
4010   regsUsed = newBitVect (ds390_nRegs);
4011   regsUsedPrologue = newBitVect (ds390_nRegs);
4012   while (lnp)
4013     {
4014       if (lnp->ic && lnp->ic->op == FUNCTION)
4015         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
4016       else
4017         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
4018
4019       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
4020           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
4021         break;
4022       if (!lnp->prev)
4023         break;
4024       lnp = lnp->prev;
4025     }
4026
4027   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
4028       && !bitVectBitValue (regsUsed, DPS_IDX))
4029     {
4030       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
4031     }
4032
4033   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
4034       && !bitVectBitValue (regsUsed, CND_IDX))
4035     {
4036       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4037       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
4038           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
4039         bitVectUnSetBit (regsUsed, CND_IDX);
4040     }
4041   else
4042     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
4043
4044   /* If this was an interrupt handler that called another function */
4045   /* function, then assume working registers may be modified by it. */
4046   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
4047     {
4048       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
4049       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
4050       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
4051       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
4052       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
4053       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
4054       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
4055       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
4056       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4057       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4058       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4059     }
4060
4061   /* Remove the unneeded push/pops */
4062   regsUnneeded = newBitVect (ds390_nRegs);
4063   while (lnp)
4064     {
4065       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4066         {
4067           if (!strncmp(lnp->line, "push", 4))
4068             {
4069               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4070               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4071                 {
4072                   connectLine (lnp->prev, lnp->next);
4073                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4074                 }
4075             }
4076           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4077             {
4078               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4079               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4080                 {
4081                   connectLine (lnp->prev, lnp->next);
4082                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4083                 }
4084             }
4085         }
4086       lnp = lnp->next;
4087     }
4088
4089   for (idx = 0; idx < regsUnneeded->size; idx++)
4090     if (bitVectBitValue (regsUnneeded, idx))
4091       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4092
4093   freeBitVect (regsUnneeded);
4094   freeBitVect (regsUsed);
4095   freeBitVect (regsUsedPrologue);
4096 }
4097
4098 /*-----------------------------------------------------------------*/
4099 /* genJavaNativeRet - generate code for return JavaNative          */
4100 /*-----------------------------------------------------------------*/
4101 static void genJavaNativeRet(iCode *ic)
4102 {
4103     int i, size;
4104
4105     aopOp (IC_LEFT (ic), ic, FALSE,
4106            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4107     size = AOP_SIZE (IC_LEFT (ic));
4108
4109     assert (size <= 4);
4110
4111     /* it is assigned to GPR0-R3 then push them */
4112     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4113         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4114         for (i = 0 ; i < size ; i++ ) {
4115             emitcode ("push","%s",
4116                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4117         }
4118         for (i = (size-1) ; i >= 0 ; i--) {
4119             emitcode ("pop","a%s",javaRet[i]);
4120         }
4121     } else {
4122         for (i = 0 ; i < size ; i++)
4123             emitcode ("mov","%s,%s",javaRet[i],
4124                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4125     }
4126     for (i = size ; i < 4 ; i++ )
4127             emitcode ("mov","%s,#0",javaRet[i]);
4128     return;
4129 }
4130
4131 /*-----------------------------------------------------------------*/
4132 /* genRet - generate code for return statement                     */
4133 /*-----------------------------------------------------------------*/
4134 static void
4135 genRet (iCode * ic)
4136 {
4137   int size, offset = 0, pushed = 0;
4138
4139   D (emitcode (";", "genRet"));
4140
4141   /* if we have no return value then
4142      just generate the "ret" */
4143   if (!IC_LEFT (ic))
4144     goto jumpret;
4145
4146   /* if this is a JavaNative function then return
4147      value in different register */
4148   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4149       genJavaNativeRet(ic);
4150       goto jumpret;
4151   }
4152   /* we have something to return then
4153      move the return value into place */
4154   aopOp (IC_LEFT (ic), ic, FALSE,
4155          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4156   size = AOP_SIZE (IC_LEFT (ic));
4157
4158   _startLazyDPSEvaluation ();
4159
4160   if (IS_BIT(_G.currentFunc->etype))
4161     {
4162       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4163       size = 0;
4164     }
4165
4166   while (size--)
4167     {
4168       char *l;
4169       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4170         {
4171           l = aopGet (IC_LEFT (ic), offset++,
4172                       FALSE, TRUE, NULL);
4173           emitcode ("push", "%s", l);
4174           pushed++;
4175         }
4176       else
4177         {
4178           /* Since A is the last element of fReturn,
4179            * it is OK to clobber it in the aopGet.
4180            */
4181           l = aopGet (IC_LEFT (ic), offset,
4182                       FALSE, FALSE, NULL);
4183           if (strcmp (fReturn[offset], l))
4184             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4185         }
4186     }
4187   _endLazyDPSEvaluation ();
4188
4189   while (pushed)
4190     {
4191       pushed--;
4192       if (strcmp (fReturn[pushed], "a"))
4193         emitcode ("pop", fReturn[pushed]);
4194       else
4195         emitcode ("pop", "acc");
4196     }
4197   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4198
4199 jumpret:
4200   /* generate a jump to the return label
4201      if the next is not the return statement */
4202   if (!(ic->next && ic->next->op == LABEL &&
4203         IC_LABEL (ic->next) == returnLabel))
4204
4205     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4206
4207 }
4208
4209 /*-----------------------------------------------------------------*/
4210 /* genLabel - generates a label                                    */
4211 /*-----------------------------------------------------------------*/
4212 static void
4213 genLabel (iCode * ic)
4214 {
4215   /* special case never generate */
4216   if (IC_LABEL (ic) == entryLabel)
4217     return;
4218
4219   D (emitcode (";", "genLabel"));
4220
4221   emitLabel (IC_LABEL (ic));
4222 }
4223
4224 /*-----------------------------------------------------------------*/
4225 /* genGoto - generates a ljmp                                      */
4226 /*-----------------------------------------------------------------*/
4227 static void
4228 genGoto (iCode * ic)
4229 {
4230   D (emitcode (";", "genGoto"));
4231
4232   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4233 }
4234
4235 /*-----------------------------------------------------------------*/
4236 /* findLabelBackwards: walks back through the iCode chain looking  */
4237 /* for the given label. Returns number of iCode instructions     */
4238 /* between that label and given ic.          */
4239 /* Returns zero if label not found.          */
4240 /*-----------------------------------------------------------------*/
4241 static int
4242 findLabelBackwards (iCode * ic, int key)
4243 {
4244   int count = 0;
4245
4246   while (ic->prev)
4247     {
4248       ic = ic->prev;
4249       count++;
4250
4251       /* If we have any pushes or pops, we cannot predict the distance.
4252          I don't like this at all, this should be dealt with in the
4253          back-end */
4254       if (ic->op == IPUSH || ic->op == IPOP) {
4255         return 0;
4256       }
4257
4258       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4259         {
4260           /* printf("findLabelBackwards = %d\n", count); */
4261           return count;
4262         }
4263     }
4264
4265   return 0;
4266 }
4267
4268 /*-----------------------------------------------------------------*/
4269 /* genPlusIncr :- does addition with increment if possible         */
4270 /*-----------------------------------------------------------------*/
4271 static bool
4272 genPlusIncr (iCode * ic)
4273 {
4274   unsigned int icount;
4275   unsigned int size = getDataSize (IC_RESULT (ic));
4276
4277   /* will try to generate an increment */
4278   /* if the right side is not a literal
4279      we cannot */
4280   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4281     return FALSE;
4282
4283   /* if the literal value of the right hand side
4284      is greater than 4 then it is not worth it */
4285   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4286     return FALSE;
4287
4288   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4289       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4290       while (icount--) {
4291           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4292       }
4293       return TRUE;
4294   }
4295   /* if increment 16 bits in register */
4296   if (
4297        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4298        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4299        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4300        (size > 1) &&
4301        (icount == 1))
4302     {
4303       symbol  *tlbl;
4304       int     emitTlbl;
4305       int     labelRange;
4306       char    *l;
4307
4308       /* If the next instruction is a goto and the goto target
4309        * is <= 5 instructions previous to this, we can generate
4310        * jumps straight to that target.
4311        */
4312       if (ic->next && ic->next->op == GOTO
4313           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4314           && labelRange <= 5)
4315         {
4316           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4317           tlbl = IC_LABEL (ic->next);
4318           emitTlbl = 0;
4319         }
4320       else
4321         {
4322           tlbl = newiTempLabel (NULL);
4323           emitTlbl = 1;
4324         }
4325       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4326       emitcode ("inc", "%s", l);
4327
4328       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4329           IS_AOP_PREG (IC_RESULT (ic)))
4330         {
4331           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4332         }
4333       else
4334         {
4335           emitcode ("clr", "a");
4336           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4337         }
4338
4339       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4340       emitcode ("inc", "%s", l);
4341       if (size > 2)
4342         {
4343           if (!strcmp(l, "acc"))
4344             {
4345               emitcode("jnz", "!tlabel", tlbl->key + 100);
4346             }
4347           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4348                    IS_AOP_PREG (IC_RESULT (ic)))
4349             {
4350               emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4351             }
4352           else
4353             {
4354               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4355             }
4356
4357           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4358           emitcode ("inc", "%s", l);
4359         }
4360       if (size > 3)
4361         {
4362           if (!strcmp(l, "acc"))
4363             {
4364               emitcode("jnz", "!tlabel", tlbl->key + 100);
4365             }
4366           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4367                    IS_AOP_PREG (IC_RESULT (ic)))
4368             {
4369               emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4370             }
4371           else
4372             {
4373               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4374             }
4375
4376           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4377           emitcode ("inc", "%s", l);
4378         }
4379
4380       if (emitTlbl)
4381         {
4382           emitLabel (tlbl);
4383         }
4384       return TRUE;
4385     }
4386
4387   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4388       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4389       options.model == MODEL_FLAT24 )
4390     {
4391       if (IC_RESULT(ic)->isGptr)
4392         {
4393           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4394         }
4395       switch (size) {
4396       case 3:
4397           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4398       case 2:
4399           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4400       case 1:
4401           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4402           break;
4403       }
4404       while (icount--)
4405         emitcode ("inc", "dptr");
4406       return TRUE;
4407     }
4408
4409   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4410       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4411       icount <= 5 )
4412     {
4413       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4414       while (icount--)
4415         emitcode ("inc", "dptr");
4416       emitcode ("mov", "dps,#0");
4417       return TRUE;
4418     }
4419
4420   /* if the sizes are greater than 1 then we cannot */
4421   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4422       AOP_SIZE (IC_LEFT (ic)) > 1)
4423     return FALSE;
4424
4425   /* we can if the aops of the left & result match or
4426      if they are in registers and the registers are the
4427      same */
4428   if (
4429        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4430        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4431        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4432     {
4433       if (icount > 3)
4434         {
4435           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4436           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4437           aopPut (IC_RESULT (ic), "a", 0);
4438         }
4439       else
4440         {
4441           _startLazyDPSEvaluation ();
4442           while (icount--)
4443             {
4444               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4445             }
4446           _endLazyDPSEvaluation ();
4447         }
4448
4449       return TRUE;
4450     }
4451
4452   return FALSE;
4453 }
4454
4455 /*-----------------------------------------------------------------*/
4456 /* outBitAcc - output a bit in acc                                 */
4457 /*-----------------------------------------------------------------*/
4458 static void
4459 outBitAcc (operand * result)
4460 {
4461   symbol *tlbl = newiTempLabel (NULL);
4462   /* if the result is a bit */
4463   if (AOP_TYPE (result) == AOP_CRY)
4464     {
4465       aopPut (result, "a", 0);
4466     }
4467   else
4468     {
4469       emitcode ("jz", "!tlabel", tlbl->key + 100);
4470       emitcode ("mov", "a,%s", one);
4471       emitLabel (tlbl);
4472       outAcc (result);
4473     }
4474 }
4475
4476 /*-----------------------------------------------------------------*/
4477 /* genPlusBits - generates code for addition of two bits           */
4478 /*-----------------------------------------------------------------*/
4479 static void
4480 genPlusBits (iCode * ic)
4481 {
4482   D (emitcode (";", "genPlusBits"));
4483
4484   emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4485   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4486     {
4487       symbol *lbl = newiTempLabel (NULL);
4488       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4489       emitcode ("cpl", "c");
4490       emitLabel (lbl);
4491       outBitC (IC_RESULT (ic));
4492     }
4493   else
4494     {
4495       emitcode ("clr", "a");
4496       emitcode ("rlc", "a");
4497       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4498       emitcode ("addc", "a,%s", zero);
4499       outAcc (IC_RESULT (ic));
4500     }
4501 }
4502
4503 static void
4504 adjustArithmeticResult (iCode * ic)
4505 {
4506   if (opIsGptr (IC_RESULT (ic)) &&
4507       opIsGptr (IC_LEFT (ic)) &&
4508       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4509     {
4510       aopPut (IC_RESULT (ic),
4511               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4512               GPTRSIZE - 1);
4513     }
4514
4515   if (opIsGptr (IC_RESULT (ic)) &&
4516       opIsGptr (IC_RIGHT (ic)) &&
4517       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4518     {
4519       aopPut (IC_RESULT (ic),
4520               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4521               GPTRSIZE - 1);
4522     }
4523
4524   if (opIsGptr (IC_RESULT (ic)) &&
4525       IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4526       IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4527       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4528       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4529     {
4530       char buffer[5];
4531       SNPRINTF (buffer, sizeof(buffer),
4532                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4533       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4534     }
4535 }
4536
4537 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4538 // generates the result if possible. If result is generated, returns TRUE; otherwise
4539 // returns false and caller must deal with fact that result isn't aopOp'd.
4540 bool aopOp3(iCode * ic)
4541 {
4542     bool dp1InUse, dp2InUse;
4543     bool useDp2;
4544
4545     // First, generate the right opcode. DPTR may be used if neither left nor result are
4546     // of type AOP_STR.
4547
4548 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4549 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4550 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4551 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4552 //      );
4553 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4554 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4555 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4556 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4557 //      );
4558
4559     // Right uses DPTR unless left or result is an AOP_STR; however,
4560     // if right is an AOP_STR, it must use DPTR regardless.
4561     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4562      && !AOP_IS_STR (IC_RIGHT (ic)))
4563     {
4564         useDp2 = TRUE;
4565     }
4566     else
4567     {
4568         useDp2 = FALSE;
4569     }
4570
4571     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4572
4573     // if the right used DPTR, left MUST use DPTR2.
4574     // if the right used DPTR2, left MUST use DPTR.
4575     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4576     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4577     // enabling us to assign DPTR to result.
4578
4579     if (AOP_USESDPTR (IC_RIGHT (ic)))
4580     {
4581         useDp2 = TRUE;
4582     }
4583     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4584     {
4585         useDp2 = FALSE;
4586     }
4587     else
4588     {
4589         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4590         {
4591             useDp2 = TRUE;
4592         }
4593         else
4594         {
4595             useDp2 = FALSE;
4596         }
4597     }
4598
4599     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4600
4601
4602     // We've op'd the left & right. So, if left or right are the same operand as result,
4603     // we know aopOp will succeed, and we can just do it & bail.
4604     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4605       {
4606         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4607         return TRUE;
4608       }
4609     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4610       {
4611 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4612         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4613         return TRUE;
4614       }
4615
4616     // Operands may be equivalent (but not equal) if they share a spill location. If
4617     // so, use the same DPTR or DPTR2.
4618     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4619       {
4620         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4621         return TRUE;
4622       }
4623     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4624       {
4625         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4626         return TRUE;
4627       }
4628
4629     // Note which dptrs are currently in use.
4630     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4631     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4632
4633     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4634     // generate it.
4635     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4636     {
4637         return FALSE;
4638     }
4639
4640     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4641     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4642     {
4643         return FALSE;
4644     }
4645
4646     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4647     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4648     {
4649         return FALSE;
4650     }
4651
4652     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4653
4654     // Some sanity checking...
4655     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4656     {
4657         fprintf(stderr,
4658                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4659                 __FILE__, __LINE__, ic->filename, ic->lineno);
4660         emitcode(";", ">>> unexpected DPTR here.");
4661     }
4662
4663     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4664     {
4665         fprintf(stderr,
4666                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4667                 __FILE__, __LINE__, ic->filename, ic->lineno);
4668         emitcode(";", ">>> unexpected DPTR2 here.");
4669     }
4670
4671     return TRUE;
4672 }
4673
4674 // Macro to aopOp all three operands of an ic. If this cannot be done,
4675 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4676 // will be set TRUE. The caller must then handle the case specially, noting
4677 // that the IC_RESULT operand is not aopOp'd.
4678 //
4679 #define AOP_OP_3_NOFATAL(ic, rc) \
4680             do { rc = !aopOp3(ic); } while (0)
4681
4682 // aopOp the left & right operands of an ic.
4683 #define AOP_OP_2(ic) \
4684     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4685     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4686
4687 // convienience macro.
4688 #define AOP_SET_LOCALS(ic) \
4689     left = IC_LEFT(ic); \
4690     right = IC_RIGHT(ic); \
4691     result = IC_RESULT(ic);
4692
4693
4694 // Given an integer value of pushedSize bytes on the stack,
4695 // adjust it to be resultSize bytes, either by discarding
4696 // the most significant bytes or by zero-padding.
4697 //
4698 // On exit from this macro, pushedSize will have been adjusted to
4699 // equal resultSize, and ACC may be trashed.
4700 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4701       /* If the pushed data is bigger than the result,          \
4702        * simply discard unused bytes. Icky, but works.          \
4703        */                                                       \
4704       while (pushedSize > resultSize)                           \
4705       {                                                         \
4706           D (emitcode (";", "discarding unused result byte.")); \
4707           emitcode ("pop", "acc");                              \
4708           pushedSize--;                                         \
4709       }                                                         \
4710       if (pushedSize < resultSize)                              \
4711       {                                                         \
4712           emitcode ("clr", "a");                                \
4713           /* Conversly, we haven't pushed enough here.          \
4714            * just zero-pad, and all is well.                    \
4715            */                                                   \
4716           while (pushedSize < resultSize)                       \
4717           {                                                     \
4718               emitcode("push", "acc");                          \
4719               pushedSize++;                                     \
4720           }                                                     \
4721       }                                                         \
4722       assert(pushedSize == resultSize);
4723
4724 /*-----------------------------------------------------------------*/
4725 /* genPlus - generates code for addition                           */
4726 /*-----------------------------------------------------------------*/
4727 static void
4728 genPlus (iCode * ic)
4729 {
4730   int size, offset = 0;
4731   bool pushResult;
4732   int rSize;
4733   bool swappedLR = FALSE;
4734
4735   D (emitcode (";", "genPlus"));
4736
4737   /* special cases :- */
4738   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4739       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4740       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4741       size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4742       if (size <= 9) {
4743           while (size--) emitcode ("inc","dptr");
4744       } else {
4745           emitcode ("mov", "a,dpl");
4746           emitcode ("add", "a,#!constbyte", size & 0xff);
4747           emitcode ("mov", "dpl,a");
4748           emitcode ("mov", "a,dph");
4749           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4750           emitcode ("mov", "dph,a");
4751           emitcode ("mov", "a,dpx");
4752           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4753           emitcode ("mov", "dpx,a");
4754       }
4755       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4756       return ;
4757   }
4758   if ( IS_SYMOP (IC_LEFT (ic)) &&
4759        OP_SYMBOL (IC_LEFT (ic))->remat &&
4760        isOperandInFarSpace (IC_RIGHT (ic))) {
4761       operand *op = IC_RIGHT(ic);
4762       IC_RIGHT(ic) = IC_LEFT(ic);
4763       IC_LEFT(ic) = op;
4764   }
4765
4766   AOP_OP_3_NOFATAL (ic, pushResult);
4767
4768   if (pushResult)
4769     {
4770       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4771     }
4772
4773   if (!pushResult)
4774     {
4775       /* if literal, literal on the right or
4776          if left requires ACC or right is already
4777          in ACC */
4778       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4779           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4780           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4781         {
4782           operand *t = IC_RIGHT (ic);
4783           IC_RIGHT (ic) = IC_LEFT (ic);
4784           IC_LEFT (ic) = t;
4785           swappedLR = TRUE;
4786           D (emitcode (";", "Swapped plus args."));
4787         }
4788
4789       /* if both left & right are in bit
4790          space */
4791       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4792           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4793         {
4794           genPlusBits (ic);
4795           goto release;
4796         }
4797
4798       /* if left in bit space & right literal */
4799       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4800           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4801         {
4802           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4803           /* if result in bit space */
4804           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4805             {
4806               if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4807                 emitcode ("cpl", "c");
4808               outBitC (IC_RESULT (ic));
4809             }
4810           else
4811             {
4812               size = getDataSize (IC_RESULT (ic));
4813               _startLazyDPSEvaluation ();
4814               while (size--)
4815                 {
4816                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4817                   emitcode ("addc", "a,%s", zero);
4818                   aopPut (IC_RESULT (ic), "a", offset++);
4819                 }
4820               _endLazyDPSEvaluation ();
4821             }
4822           goto release;
4823         }
4824
4825       /* if I can do an increment instead
4826          of add then GOOD for ME */
4827       if (genPlusIncr (ic) == TRUE)
4828         {
4829           D (emitcode (";", "did genPlusIncr"));
4830           goto release;
4831         }
4832
4833     }
4834   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4835
4836   _startLazyDPSEvaluation ();
4837   while (size--)
4838     {
4839       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4840         {
4841           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4842           if (offset == 0)
4843             emitcode ("add", "a,%s",
4844                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4845           else
4846             emitcode ("addc", "a,%s",
4847                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4848         }
4849       else
4850         {
4851           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4852           {
4853               /* right is going to use ACC or we would have taken the
4854                * above branch.
4855                */
4856               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4857               TR_AP("#3");
4858               D(emitcode(";", "+ AOP_ACC special case."););
4859               emitcode("xch", "a, %s", DP2_RESULT_REG);
4860           }
4861           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4862           if (offset == 0)
4863           {
4864             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4865             {
4866                 TR_AP("#4");
4867                 emitcode("add", "a, %s", DP2_RESULT_REG);
4868             }
4869             else
4870             {
4871                 emitcode ("add", "a,%s",
4872                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4873                                   DP2_RESULT_REG));
4874             }
4875           }
4876           else
4877           {
4878             emitcode ("addc", "a,%s",
4879                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4880                           DP2_RESULT_REG));
4881           }
4882         }
4883       if (!pushResult)
4884         {
4885           aopPut (IC_RESULT (ic), "a", offset);
4886         }
4887       else
4888         {
4889           emitcode ("push", "acc");
4890         }
4891       offset++;
4892     }
4893   _endLazyDPSEvaluation ();
4894
4895   if (pushResult)
4896     {
4897       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4898
4899       size = getDataSize (IC_LEFT (ic));
4900       rSize = getDataSize (IC_RESULT (ic));
4901
4902       ADJUST_PUSHED_RESULT(size, rSize);
4903
4904       _startLazyDPSEvaluation ();
4905       while (size--)
4906         {
4907           emitcode ("pop", "acc");
4908           aopPut (IC_RESULT (ic), "a", size);
4909         }
4910       _endLazyDPSEvaluation ();
4911     }
4912
4913   adjustArithmeticResult (ic);
4914
4915 release:
4916   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4917   if (!swappedLR)
4918     {
4919       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4920       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4921     }
4922   else
4923     {
4924       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4925       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4926     }
4927 }
4928
4929 /*-----------------------------------------------------------------*/
4930 /* genMinusDec :- does subtraction with decrement if possible      */
4931 /*-----------------------------------------------------------------*/
4932 static bool
4933 genMinusDec (iCode * ic)
4934 {
4935   unsigned int icount;
4936   unsigned int size = getDataSize (IC_RESULT (ic));
4937
4938   /* will try to generate an increment */
4939   /* if the right side is not a literal
4940      we cannot */
4941   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4942     return FALSE;
4943
4944   /* if the literal value of the right hand side
4945      is greater than 4 then it is not worth it */
4946   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4947     return FALSE;
4948
4949   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4950       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4951       while (icount--) {
4952           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4953       }
4954       return TRUE;
4955   }
4956   /* if decrement 16 bits in register */
4957   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4958       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4959       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4960       (size > 1) &&
4961       (icount == 1))
4962     {
4963       symbol *tlbl;
4964       int    emitTlbl;
4965       int    labelRange;
4966       char   *l;
4967
4968       /* If the next instruction is a goto and the goto target
4969          * is <= 5 instructions previous to this, we can generate
4970          * jumps straight to that target.
4971        */
4972       if (ic->next && ic->next->op == GOTO
4973           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4974           && labelRange <= 5)
4975         {
4976           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4977           tlbl = IC_LABEL (ic->next);
4978           emitTlbl = 0;
4979         }
4980       else
4981         {
4982           tlbl = newiTempLabel (NULL);
4983           emitTlbl = 1;
4984         }
4985
4986       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4987       emitcode ("dec", "%s", l);
4988
4989       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4990           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4991           IS_AOP_PREG (IC_RESULT (ic)))
4992         {
4993           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4994         }
4995       else
4996         {
4997           emitcode ("mov", "a,#!constbyte",0xff);
4998           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4999         }
5000       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
5001       emitcode ("dec", "%s", l);
5002       if (size > 2)
5003         {
5004           if (!strcmp(l, "acc"))
5005             {
5006               emitcode("jnz", "!tlabel", tlbl->key + 100);
5007             }
5008           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
5009                    AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
5010                    IS_AOP_PREG (IC_RESULT (ic)))
5011             {
5012               emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
5013             }
5014           else
5015             {
5016               emitcode ("mov", "a,#!constbyte",0xff);
5017               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5018             }
5019           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
5020           emitcode ("dec", "%s", l);
5021         }
5022       if (size > 3)
5023         {
5024           if (!strcmp(l, "acc"))
5025             {
5026               emitcode("jnz", "!tlabel", tlbl->key + 100);
5027             }
5028           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
5029                    AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
5030                    IS_AOP_PREG (IC_RESULT (ic)))
5031             {
5032               emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
5033             }
5034           else
5035             {
5036               emitcode ("mov", "a,#!constbyte",0xff);
5037               emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
5038             }
5039           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
5040           emitcode ("dec", "%s", l);
5041         }
5042       if (emitTlbl)
5043         {
5044           emitLabel (tlbl);
5045         }
5046       return TRUE;
5047     }
5048
5049   /* if the sizes are greater than 1 then we cannot */
5050   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
5051       AOP_SIZE (IC_LEFT (ic)) > 1)
5052     return FALSE;
5053
5054   /* we can if the aops of the left & result match or
5055      if they are in registers and the registers are the
5056      same */
5057   if (
5058        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5059        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5060        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5061     {
5062       char *l;
5063
5064       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5065         {
5066           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5067           l = "a";
5068         }
5069       else
5070         {
5071           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5072         }
5073
5074       _startLazyDPSEvaluation ();
5075       while (icount--)
5076         {
5077           emitcode ("dec", "%s", l);
5078         }
5079       _endLazyDPSEvaluation ();
5080
5081       if (AOP_NEEDSACC (IC_RESULT (ic)))
5082         aopPut (IC_RESULT (ic), "a", 0);
5083
5084       return TRUE;
5085     }
5086
5087   return FALSE;
5088 }
5089
5090 /*-----------------------------------------------------------------*/
5091 /* addSign - complete with sign                                    */
5092 /*-----------------------------------------------------------------*/
5093 static void
5094 addSign (operand * result, int offset, int sign)
5095 {
5096   int size = (getDataSize (result) - offset);
5097   if (size > 0)
5098     {
5099       _startLazyDPSEvaluation();
5100       if (sign)
5101         {
5102           emitcode ("rlc", "a");
5103           emitcode ("subb", "a,acc");
5104           while (size--)
5105             {
5106               aopPut (result, "a", offset++);
5107             }
5108         }
5109       else
5110         {
5111           while (size--)
5112             {
5113               aopPut (result, zero, offset++);
5114             }
5115         }
5116       _endLazyDPSEvaluation();
5117     }
5118 }
5119
5120 /*-----------------------------------------------------------------*/
5121 /* genMinusBits - generates code for subtraction  of two bits      */
5122 /*-----------------------------------------------------------------*/
5123 static void
5124 genMinusBits (iCode * ic)
5125 {
5126   symbol *lbl = newiTempLabel (NULL);
5127
5128   D (emitcode (";", "genMinusBits"));
5129
5130   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5131     {
5132       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5133       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5134       emitcode ("cpl", "c");
5135       emitLabel (lbl);
5136       outBitC (IC_RESULT (ic));
5137     }
5138   else
5139     {
5140       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5141       emitcode ("subb", "a,acc");
5142       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5143       emitcode ("inc", "a");
5144       emitLabel (lbl);
5145       aopPut (IC_RESULT (ic), "a", 0);
5146       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5147     }
5148 }
5149
5150 /*-----------------------------------------------------------------*/
5151 /* genMinus - generates code for subtraction                       */
5152 /*-----------------------------------------------------------------*/
5153 static void
5154 genMinus (iCode * ic)
5155 {
5156     int size, offset = 0;
5157     int rSize;
5158     long lit = 0L;
5159     bool pushResult;
5160
5161     D (emitcode (";", "genMinus"));
5162
5163     AOP_OP_3_NOFATAL(ic, pushResult);
5164
5165     if (!pushResult)
5166     {
5167       /* special cases :- */
5168       /* if both left & right are in bit space */
5169       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5170           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5171         {
5172           genMinusBits (ic);
5173           goto release;
5174         }
5175
5176       /* if I can do an decrement instead
5177          of subtract then GOOD for ME */
5178       if (genMinusDec (ic) == TRUE)
5179         goto release;
5180
5181     }
5182
5183   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5184
5185   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5186     {
5187       CLRC;
5188     }
5189   else
5190     {
5191       lit = (long) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5192       lit = -lit;
5193     }
5194
5195
5196   /* if literal, add a,#-lit, else normal subb */
5197   _startLazyDPSEvaluation ();
5198   while (size--) {
5199       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5200           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5201               emitcode ("mov","b,%s",
5202                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5203               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5204               emitcode ("subb","a,b");
5205           } else {
5206               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5207               emitcode ("subb", "a,%s",
5208                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5209                                 DP2_RESULT_REG));
5210           }
5211       } else {
5212           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5213           /* first add without previous c */
5214           if (!offset) {
5215               if (!size && lit==-1) {
5216                   emitcode ("dec", "a");
5217               } else {
5218                   emitcode ("add", "a,#!constbyte",
5219                             (unsigned int) (lit & 0x0FFL));
5220               }
5221           } else {
5222               emitcode ("addc", "a,#!constbyte",
5223                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5224           }
5225       }
5226
5227       if (pushResult) {
5228           emitcode ("push", "acc");
5229       } else {
5230           aopPut (IC_RESULT (ic), "a", offset);
5231       }
5232       offset++;
5233   }
5234   _endLazyDPSEvaluation ();
5235
5236   if (pushResult)
5237     {
5238       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5239
5240       size = getDataSize (IC_LEFT (ic));
5241       rSize = getDataSize (IC_RESULT (ic));
5242
5243       ADJUST_PUSHED_RESULT(size, rSize);
5244
5245       _startLazyDPSEvaluation ();
5246       while (size--)
5247         {
5248           emitcode ("pop", "acc");
5249           aopPut (IC_RESULT (ic), "a", size);
5250         }
5251       _endLazyDPSEvaluation ();
5252     }
5253
5254   adjustArithmeticResult (ic);
5255
5256 release:
5257   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5258   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5259   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5260 }
5261
5262
5263 /*-----------------------------------------------------------------*/
5264 /* genMultbits :- multiplication of bits                           */
5265 /*-----------------------------------------------------------------*/
5266 static void
5267 genMultbits (operand * left,
5268              operand * right,
5269              operand * result,
5270              iCode   * ic)
5271 {
5272   D (emitcode (";", "genMultbits"));
5273
5274   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5275   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5276   aopOp(result, ic, TRUE, FALSE);
5277   outBitC (result);
5278 }
5279
5280 /*-----------------------------------------------------------------*/
5281 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5282 /*-----------------------------------------------------------------*/
5283 static void
5284 genMultOneByte (operand * left,
5285                 operand * right,
5286                 operand * result,
5287                 iCode   * ic)
5288 {
5289   symbol *lbl;
5290   int size;
5291   bool runtimeSign, compiletimeSign;
5292   bool lUnsigned, rUnsigned, pushedB;
5293
5294   /* (if two literals: the value is computed before) */
5295   /* if one literal, literal on the right */
5296   if (AOP_TYPE (left) == AOP_LIT)
5297     {
5298       operand *t = right;
5299       right = left;
5300       left = t;
5301       /* emitcode (";", "swapped left and right"); */
5302     }
5303   /* if no literal, unsigned on the right: shorter code */
5304   if (   AOP_TYPE (right) != AOP_LIT
5305       && SPEC_USIGN (getSpec (operandType (left))))
5306     {
5307       operand *t = right;
5308       right = left;
5309       left = t;
5310     }
5311
5312   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5313   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5314
5315   pushedB = pushB ();
5316
5317   if ((lUnsigned && rUnsigned)
5318 /* sorry, I don't know how to get size
5319    without calling aopOp (result,...);
5320    see Feature Request  */
5321       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5322                    no need to take care about the signedness! */
5323     {
5324       /* just an unsigned 8 * 8 = 8 multiply
5325          or 8u * 8u = 16u */
5326       /* emitcode (";","unsigned"); */
5327       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5328       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5329       emitcode ("mul", "ab");
5330
5331       _G.accInUse++;
5332       aopOp (result, ic, TRUE, FALSE);
5333       size = AOP_SIZE (result);
5334
5335       if (size < 1 || size > 2)
5336         {
5337           /* this should never happen */
5338           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5339                    size, __FILE__, lineno);
5340           exit (1);
5341         }
5342
5343       aopPut (result, "a", 0);
5344       _G.accInUse--;
5345       if (size == 2)
5346         aopPut (result, "b", 1);
5347
5348       popB (pushedB);
5349       return;
5350     }
5351
5352   /* we have to do a signed multiply */
5353   /* emitcode (";", "signed"); */
5354
5355   /* now sign adjust for both left & right */
5356
5357   /* let's see what's needed: */
5358   /* apply negative sign during runtime */
5359   runtimeSign = FALSE;
5360   /* negative sign from literals */
5361   compiletimeSign = FALSE;
5362
5363   if (!lUnsigned)
5364     {
5365       if (AOP_TYPE(left) == AOP_LIT)
5366         {
5367           /* signed literal */
5368           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5369           if (val < 0)
5370             compiletimeSign = TRUE;
5371         }
5372       else
5373         /* signed but not literal */
5374         runtimeSign = TRUE;
5375     }
5376
5377   if (!rUnsigned)
5378     {
5379       if (AOP_TYPE(right) == AOP_LIT)
5380         {
5381           /* signed literal */
5382           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5383           if (val < 0)
5384             compiletimeSign ^= TRUE;
5385         }
5386       else
5387         /* signed but not literal */
5388         runtimeSign = TRUE;
5389     }
5390
5391   /* initialize F0, which stores the runtime sign */
5392   if (runtimeSign)
5393     {
5394       if (compiletimeSign)
5395         emitcode ("setb", "F0"); /* set sign flag */
5396       else
5397         emitcode ("clr", "F0"); /* reset sign flag */
5398     }
5399
5400   /* save the signs of the operands */
5401   if (AOP_TYPE(right) == AOP_LIT)
5402     {
5403       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5404
5405       if (!rUnsigned && val < 0)
5406         emitcode ("mov", "b,#!constbyte", -val);
5407       else
5408         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5409     }
5410   else /* ! literal */
5411     {
5412       if (rUnsigned)  /* emitcode (";", "signed"); */
5413         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5414       else
5415         {
5416           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5417           lbl = newiTempLabel (NULL);
5418           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5419           emitcode ("cpl", "F0"); /* complement sign flag */
5420           emitcode ("cpl", "a");  /* 2's complement */
5421           emitcode ("inc", "a");
5422           emitLabel (lbl);
5423           emitcode ("mov", "b,a");
5424         }
5425     }
5426
5427   if (AOP_TYPE(left) == AOP_LIT)
5428     {
5429       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5430
5431       if (!lUnsigned && val < 0)
5432         emitcode ("mov", "a,#!constbyte", -val);
5433       else
5434         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5435     }
5436   else /* ! literal */
5437     {
5438       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5439
5440       if (!lUnsigned)  /* emitcode (";", "signed"); */
5441         {
5442           lbl = newiTempLabel (NULL);
5443           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5444           emitcode ("cpl", "F0"); /* complement sign flag */
5445           emitcode ("cpl", "a");  /* 2's complement */
5446           emitcode ("inc", "a");
5447           emitLabel (lbl);
5448         }
5449     }
5450
5451   /* now the multiplication */
5452   emitcode ("mul", "ab");
5453   _G.accInUse++;
5454   aopOp(result, ic, TRUE, FALSE);
5455   size = AOP_SIZE (result);
5456
5457   if (size < 1 || size > 2)
5458     {
5459       /* this should never happen */
5460       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5461                size, __FILE__, lineno);
5462       exit (1);
5463     }
5464
5465   if (runtimeSign || compiletimeSign)
5466     {
5467       lbl = newiTempLabel (NULL);
5468       if (runtimeSign)
5469         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5470       emitcode ("cpl", "a"); /* lsb 2's complement */
5471       if (size != 2)
5472         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5473       else
5474         {
5475           emitcode ("add", "a,#0x01"); /* this sets carry flag */
5476           emitcode ("xch", "a,b");
5477           emitcode ("cpl", "a"); /* msb 2's complement */
5478           emitcode ("addc", "a,#0x00");
5479           emitcode ("xch", "a,b");
5480         }
5481       emitLabel (lbl);
5482     }
5483   aopPut (result, "a", 0);
5484   _G.accInUse--;
5485   if (size == 2)
5486     aopPut (result, "b", 1);
5487
5488   popB (pushedB);
5489 }
5490
5491 /*-----------------------------------------------------------------*/
5492 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5493 /*-----------------------------------------------------------------*/
5494 static void genMultTwoByte (operand *left, operand *right,
5495                             operand *result, iCode *ic)
5496 {
5497         sym_link *retype = getSpec(operandType(right));
5498         sym_link *letype = getSpec(operandType(left));
5499         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5500         symbol *lbl;
5501
5502         if (AOP_TYPE (left) == AOP_LIT) {
5503                 operand *t = right;
5504                 right = left;
5505                 left = t;
5506         }
5507         /* save EA bit in F1 */
5508         lbl = newiTempLabel(NULL);
5509         emitcode ("setb","F1");
5510         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5511         emitcode ("clr","F1");
5512         emitLabel (lbl);
5513
5514         /* load up MB with right */
5515         if (!umult) {
5516                 emitcode("clr","F0");
5517                 if (AOP_TYPE(right) == AOP_LIT) {
5518                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5519                         if (val < 0) {
5520                                 emitcode("setb","F0");
5521                                 val = -val;
5522                         }
5523                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5524                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5525                 } else {
5526                         lbl = newiTempLabel(NULL);
5527                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5528                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5529                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5530                         emitcode ("xch", "a,b");
5531                         emitcode ("cpl","a");
5532                         emitcode ("add", "a,#1");
5533                         emitcode ("xch", "a,b");
5534                         emitcode ("cpl", "a"); // msb
5535                         emitcode ("addc", "a,#0");
5536                         emitcode ("setb","F0");
5537                         emitLabel (lbl);
5538                         emitcode ("mov","mb,b");
5539                         emitcode ("mov","mb,a");
5540                 }
5541         } else {
5542                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5543                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5544         }
5545         /* load up MA with left */
5546         if (!umult) {
5547                 lbl = newiTempLabel(NULL);
5548                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5549                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5550                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5551                 emitcode ("xch", "a,b");
5552                 emitcode ("cpl","a");
5553                 emitcode ("add", "a,#1");
5554                 emitcode ("xch", "a,b");
5555                 emitcode ("cpl", "a"); // msb
5556                 emitcode ("addc","a,#0");
5557                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5558                 emitcode ("setb","F0");
5559                 emitLabel (lbl);
5560                 emitcode ("mov","ma,b");
5561                 emitcode ("mov","ma,a");
5562         } else {
5563                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5564                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5565         }
5566         /* wait for multiplication to finish */
5567         lbl = newiTempLabel(NULL);
5568         emitLabel (lbl);
5569         emitcode("mov","a,mcnt1");
5570         emitcode("anl","a,#!constbyte",0x80);
5571         emitcode("jnz","!tlabel",lbl->key+100);
5572
5573         freeAsmop (left, NULL, ic, TRUE);
5574         freeAsmop (right, NULL, ic,TRUE);
5575         aopOp(result, ic, TRUE, FALSE);
5576
5577         /* if unsigned then simple */
5578         if (umult) {
5579                 emitcode ("mov","a,ma");
5580                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5581                 emitcode ("mov","a,ma");
5582                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5583                 aopPut(result,"ma",1);
5584                 aopPut(result,"ma",0);
5585         } else {
5586                 emitcode("push","ma");
5587                 emitcode("push","ma");
5588                 emitcode("push","ma");
5589                 MOVA("ma");
5590                 /* negate result if needed */
5591                 lbl = newiTempLabel(NULL);
5592                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5593                 emitcode("cpl","a");
5594                 emitcode("add","a,#1");
5595                 emitLabel (lbl);
5596                 if (AOP_TYPE(result) == AOP_ACC)
5597                 {
5598                     D (emitcode(";", "ACC special case."));
5599                     /* We know result is the only live aop, and
5600                      * it's obviously not a DPTR2, so AP is available.
5601                      */
5602                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5603                 }
5604                 else
5605                 {
5606                     aopPut(result,"a",0);
5607                 }
5608
5609                 emitcode("pop","acc");
5610                 lbl = newiTempLabel(NULL);
5611                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5612                 emitcode("cpl","a");
5613                 emitcode("addc","a,#0");
5614                 emitLabel (lbl);
5615                 aopPut(result,"a",1);
5616                 emitcode("pop","acc");
5617                 if (AOP_SIZE(result) >= 3) {
5618                         lbl = newiTempLabel(NULL);
5619                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5620                         emitcode("cpl","a");
5621                         emitcode("addc","a,#0");
5622                         emitLabel (lbl);
5623                         aopPut(result,"a",2);
5624                 }
5625                 emitcode("pop","acc");
5626                 if (AOP_SIZE(result) >= 4) {
5627                         lbl = newiTempLabel(NULL);
5628                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5629                         emitcode("cpl","a");
5630                         emitcode("addc","a,#0");
5631                         emitLabel (lbl);
5632                         aopPut(result,"a",3);
5633                 }
5634                 if (AOP_TYPE(result) == AOP_ACC)
5635                 {
5636                     /* We stashed the result away above. */
5637                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5638                 }
5639
5640         }
5641         freeAsmop (result, NULL, ic, TRUE);
5642
5643         /* restore EA bit in F1 */
5644         lbl = newiTempLabel(NULL);
5645         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5646         emitcode ("setb","EA");
5647         emitLabel (lbl);
5648         return ;
5649 }
5650
5651 /*-----------------------------------------------------------------*/
5652 /* genMult - generates code for multiplication                     */
5653 /*-----------------------------------------------------------------*/
5654 static void
5655 genMult (iCode * ic)
5656 {
5657   operand *left = IC_LEFT (ic);
5658   operand *right = IC_RIGHT (ic);
5659   operand *result = IC_RESULT (ic);
5660
5661   D (emitcode (";", "genMult"));
5662
5663   /* assign the asmops */
5664   AOP_OP_2 (ic);
5665
5666   /* special cases first */
5667   /* both are bits */
5668   if (AOP_TYPE (left) == AOP_CRY &&
5669       AOP_TYPE (right) == AOP_CRY)
5670     {
5671       genMultbits (left, right, result, ic);
5672       goto release;
5673     }
5674
5675   /* if both are of size == 1 */
5676   if (AOP_SIZE (left) == 1 &&
5677       AOP_SIZE (right) == 1)
5678     {
5679       genMultOneByte (left, right, result, ic);
5680       goto release;
5681     }
5682
5683   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5684           /* use the ds390 ARITHMETIC accel UNIT */
5685           genMultTwoByte (left, right, result, ic);
5686           return ;
5687   }
5688   /* should have been converted to function call */
5689   assert (0);
5690
5691 release:
5692   freeAsmop (result, NULL, ic, TRUE);
5693   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5694   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5695 }
5696
5697 /*-----------------------------------------------------------------*/
5698 /* genDivbits :- division of bits                                  */
5699 /*-----------------------------------------------------------------*/
5700 static void
5701 genDivbits (operand * left,
5702             operand * right,
5703             operand * result,
5704             iCode   * ic)
5705 {
5706   char *l;
5707   bool pushedB;
5708
5709   D(emitcode (";", "genDivbits"));
5710
5711   pushedB = pushB ();
5712
5713   /* the result must be bit */
5714   LOAD_AB_FOR_DIV (left, right, l);
5715   emitcode ("div", "ab");
5716   emitcode ("rrc", "a");
5717   aopOp(result, ic, TRUE, FALSE);
5718
5719   popB (pushedB);
5720
5721   aopPut (result, "c", 0);
5722 }
5723
5724 /*-----------------------------------------------------------------*/
5725 /* genDivOneByte : 8 bit division                                  */
5726 /*-----------------------------------------------------------------*/
5727 static void
5728 genDivOneByte (operand * left,
5729                operand * right,
5730                operand * result,
5731                iCode   * ic)
5732 {
5733   bool lUnsigned, rUnsigned, pushedB;
5734   bool runtimeSign, compiletimeSign;
5735   char *l;
5736   symbol *lbl;
5737   int size, offset;
5738
5739   D(emitcode (";", "genDivOneByte"));
5740
5741   offset = 1;
5742   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5743   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5744
5745   pushedB = pushB ();
5746
5747   /* signed or unsigned */
5748   if (lUnsigned && rUnsigned)
5749     {
5750       /* unsigned is easy */
5751       LOAD_AB_FOR_DIV (left, right, l);
5752       emitcode ("div", "ab");
5753
5754       _G.accInUse++;
5755       aopOp (result, ic, TRUE, FALSE);
5756       aopPut (result, "a", 0);
5757       _G.accInUse--;
5758
5759       size = AOP_SIZE (result) - 1;
5760
5761       while (size--)
5762         aopPut (result, zero, offset++);
5763
5764       popB (pushedB);
5765       return;
5766     }
5767
5768   /* signed is a little bit more difficult */
5769
5770   /* now sign adjust for both left & right */
5771
5772   /* let's see what's needed: */
5773   /* apply negative sign during runtime */
5774   runtimeSign = FALSE;
5775   /* negative sign from literals */
5776   compiletimeSign = FALSE;
5777
5778   if (!lUnsigned)
5779     {
5780       if (AOP_TYPE(left) == AOP_LIT)
5781         {
5782           /* signed literal */
5783           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5784           if (val < 0)
5785             compiletimeSign = TRUE;
5786         }
5787       else
5788         /* signed but not literal */
5789         runtimeSign = TRUE;
5790     }
5791
5792   if (!rUnsigned)
5793     {
5794       if (AOP_TYPE(right) == AOP_LIT)
5795         {
5796           /* signed literal */
5797           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5798           if (val < 0)
5799             compiletimeSign ^= TRUE;
5800         }
5801       else
5802         /* signed but not literal */
5803         runtimeSign = TRUE;
5804     }
5805
5806   /* initialize F0, which stores the runtime sign */
5807   if (runtimeSign)
5808     {
5809       if (compiletimeSign)
5810         emitcode ("setb", "F0"); /* set sign flag */
5811       else
5812         emitcode ("clr", "F0"); /* reset sign flag */
5813     }
5814
5815   /* save the signs of the operands */
5816   if (AOP_TYPE(right) == AOP_LIT)
5817     {
5818       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5819
5820       if (!rUnsigned && val < 0)
5821         emitcode ("mov", "b,#0x%02x", -val);
5822       else
5823         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5824     }
5825   else /* ! literal */
5826     {
5827       if (rUnsigned)
5828         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5829       else
5830         {
5831           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5832           lbl = newiTempLabel (NULL);
5833           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5834           emitcode ("cpl", "F0"); /* complement sign flag */
5835           emitcode ("cpl", "a");  /* 2's complement */
5836           emitcode ("inc", "a");
5837           emitLabel (lbl);
5838           emitcode ("mov", "b,a");
5839         }
5840     }
5841
5842   if (AOP_TYPE(left) == AOP_LIT)
5843     {
5844       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5845
5846       if (!lUnsigned && val < 0)
5847         emitcode ("mov", "a,#0x%02x", -val);
5848       else
5849         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5850     }
5851   else /* ! literal */
5852     {
5853       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5854
5855       if (!lUnsigned)
5856         {
5857           lbl = newiTempLabel (NULL);
5858           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5859           emitcode ("cpl", "F0"); /* complement sign flag */
5860           emitcode ("cpl", "a");  /* 2's complement */
5861           emitcode ("inc", "a");
5862           emitLabel (lbl);
5863         }
5864     }
5865
5866   /* now the division */
5867   emitcode ("nop", "; workaround for DS80C390 div bug.");
5868   emitcode ("div", "ab");
5869
5870   if (runtimeSign || compiletimeSign)
5871     {
5872       lbl = newiTempLabel (NULL);
5873       if (runtimeSign)
5874         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5875       emitcode ("cpl", "a"); /* lsb 2's complement */
5876       emitcode ("inc", "a");
5877       emitLabel (lbl);
5878
5879       _G.accInUse++;
5880       aopOp (result, ic, TRUE, FALSE);
5881       size = AOP_SIZE (result) - 1;
5882
5883       if (size > 0)
5884         {
5885           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5886              then the result will be in b, a */
5887           emitcode ("mov", "b,a"); /* 1 */
5888           /* msb is 0x00 or 0xff depending on the sign */
5889           if (runtimeSign)
5890             {
5891               emitcode ("mov",  "c,F0");
5892               emitcode ("subb", "a,acc");
5893               emitcode ("xch",  "a,b"); /* 2 */
5894               while (size--)
5895                 aopPut (result, "b", offset++); /* write msb's */
5896             }
5897           else /* compiletimeSign */
5898             while (size--)
5899               aopPut (result, "#0xff", offset++); /* write msb's */
5900         }
5901       aopPut (result, "a", 0); /* 3: write lsb */
5902     }
5903   else
5904     {
5905       _G.accInUse++;
5906       aopOp(result, ic, TRUE, FALSE);
5907       size = AOP_SIZE (result) - 1;
5908
5909       aopPut (result, "a", 0);
5910       while (size--)
5911         aopPut (result, zero, offset++);
5912     }
5913   _G.accInUse--;
5914   popB (pushedB);
5915 }
5916
5917 /*-----------------------------------------------------------------*/
5918 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5919 /*-----------------------------------------------------------------*/
5920 static void genDivTwoByte (operand *left, operand *right,
5921                             operand *result, iCode *ic)
5922 {
5923         sym_link *retype = getSpec(operandType(right));
5924         sym_link *letype = getSpec(operandType(left));
5925         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5926         symbol *lbl;
5927
5928         /* save EA bit in F1 */
5929         lbl = newiTempLabel(NULL);
5930         emitcode ("setb","F1");
5931         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5932         emitcode ("clr","F1");
5933         emitLabel (lbl);
5934
5935         /* load up MA with left */
5936         if (!umult) {
5937                 emitcode("clr","F0");
5938                 lbl = newiTempLabel(NULL);
5939                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5940                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5941                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5942                 emitcode ("xch", "a,b");
5943                 emitcode ("cpl","a");
5944                 emitcode ("add", "a,#1");
5945                 emitcode ("xch", "a,b");
5946                 emitcode ("cpl", "a"); // msb
5947                 emitcode ("addc","a,#0");
5948                 emitcode ("setb","F0");
5949                 emitLabel (lbl);
5950                 emitcode ("mov","ma,b");
5951                 emitcode ("mov","ma,a");
5952         } else {
5953                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5954                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5955         }
5956
5957         /* load up MB with right */
5958         if (!umult) {
5959                 if (AOP_TYPE(right) == AOP_LIT) {
5960                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5961                         if (val < 0) {
5962                                 lbl = newiTempLabel(NULL);
5963                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5964                                 emitcode("setb","F0");
5965                                 emitLabel (lbl);
5966                                 val = -val;
5967                         }
5968                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5969                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5970                 } else {
5971                         lbl = newiTempLabel(NULL);
5972                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5973                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5974                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5975                         emitcode ("xch", "a,b");
5976                         emitcode ("cpl","a");
5977                         emitcode ("add", "a,#1");
5978                         emitcode ("xch", "a,b");
5979                         emitcode ("cpl", "a"); // msb
5980                         emitcode ("addc", "a,#0");
5981                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5982                         emitcode ("setb","F0");
5983                         emitLabel (lbl);
5984                         emitcode ("mov","mb,b");
5985                         emitcode ("mov","mb,a");
5986                 }
5987         } else {
5988                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5989                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5990         }
5991
5992         /* wait for multiplication to finish */
5993         lbl = newiTempLabel(NULL);
5994         emitLabel (lbl);
5995         emitcode("mov","a,mcnt1");
5996         emitcode("anl","a,#!constbyte",0x80);
5997         emitcode("jnz","!tlabel",lbl->key+100);
5998
5999         freeAsmop (left, NULL, ic, TRUE);
6000         freeAsmop (right, NULL, ic,TRUE);
6001         aopOp(result, ic, TRUE, FALSE);
6002
6003         /* if unsigned then simple */
6004         if (umult) {
6005                 aopPut(result,"ma",1);
6006                 aopPut(result,"ma",0);
6007         } else {
6008                 emitcode("push","ma");
6009                 MOVA("ma");
6010                 /* negate result if needed */
6011                 lbl = newiTempLabel(NULL);
6012                 emitcode("jnb","F0,!tlabel",lbl->key+100);
6013                 emitcode("cpl","a");
6014                 emitcode("add","a,#1");
6015                 emitLabel (lbl);
6016                 aopPut(result,"a",0);
6017                 emitcode("pop","acc");
6018                 lbl = newiTempLabel(NULL);
6019                 emitcode("jnb","F0,!tlabel",lbl->key+100);
6020                 emitcode("cpl","a");
6021                 emitcode("addc","a,#0");
6022                 emitLabel (lbl);
6023                 aopPut(result,"a",1);
6024         }
6025         freeAsmop (result, NULL, ic, TRUE);
6026         /* restore EA bit in F1 */
6027         lbl = newiTempLabel(NULL);
6028         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6029         emitcode ("setb","EA");
6030         emitLabel (lbl);
6031         return ;
6032 }
6033
6034 /*-----------------------------------------------------------------*/
6035 /* genDiv - generates code for division                            */
6036 /*-----------------------------------------------------------------*/
6037 static void
6038 genDiv (iCode * ic)
6039 {
6040   operand *left = IC_LEFT (ic);
6041   operand *right = IC_RIGHT (ic);
6042   operand *result = IC_RESULT (ic);
6043
6044   D (emitcode (";", "genDiv"));
6045
6046   /* assign the amsops */
6047   AOP_OP_2 (ic);
6048
6049   /* special cases first */
6050   /* both are bits */
6051   if (AOP_TYPE (left) == AOP_CRY &&
6052       AOP_TYPE (right) == AOP_CRY)
6053     {
6054       genDivbits (left, right, result, ic);
6055       goto release;
6056     }
6057
6058   /* if both are of size == 1 */
6059   if (AOP_SIZE (left) == 1 &&
6060       AOP_SIZE (right) == 1)
6061     {
6062       genDivOneByte (left, right, result, ic);
6063       goto release;
6064     }
6065
6066   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6067           /* use the ds390 ARITHMETIC accel UNIT */
6068           genDivTwoByte (left, right, result, ic);
6069           return ;
6070   }
6071   /* should have been converted to function call */
6072   assert (0);
6073 release:
6074   freeAsmop (result, NULL, ic, TRUE);
6075   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6076   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6077 }
6078
6079 /*-----------------------------------------------------------------*/
6080 /* genModbits :- modulus of bits                                   */
6081 /*-----------------------------------------------------------------*/
6082 static void
6083 genModbits (operand * left,
6084             operand * right,
6085             operand * result,
6086             iCode   * ic)
6087 {
6088   char *l;
6089   bool pushedB;
6090
6091   D (emitcode (";", "genModbits"));
6092
6093   pushedB = pushB ();
6094
6095   /* the result must be bit */
6096   LOAD_AB_FOR_DIV (left, right, l);
6097   emitcode ("div", "ab");
6098   emitcode ("mov", "a,b");
6099   emitcode ("rrc", "a");
6100   aopOp(result, ic, TRUE, FALSE);
6101
6102   popB (pushedB);
6103
6104   aopPut (result, "c", 0);
6105 }
6106
6107 /*-----------------------------------------------------------------*/
6108 /* genModOneByte : 8 bit modulus                                   */
6109 /*-----------------------------------------------------------------*/
6110 static void
6111 genModOneByte (operand * left,
6112                operand * right,
6113                operand * result,
6114                iCode   * ic)
6115 {
6116   bool lUnsigned, rUnsigned, pushedB;
6117   bool runtimeSign, compiletimeSign;
6118   char *l;
6119   symbol *lbl;
6120   int size, offset;
6121
6122   D (emitcode (";", "genModOneByte"));
6123
6124   offset = 1;
6125   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6126   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6127
6128   pushedB = pushB ();
6129
6130   /* signed or unsigned */
6131   if (lUnsigned && rUnsigned)
6132     {
6133       /* unsigned is easy */
6134       LOAD_AB_FOR_DIV (left, right, l);
6135       emitcode ("div", "ab");
6136       aopOp (result, ic, TRUE, FALSE);
6137       aopPut (result, "b", 0);
6138
6139       for (size = AOP_SIZE (result) - 1; size--;)
6140         aopPut (result, zero, offset++);
6141
6142       popB (pushedB);
6143       return;
6144     }
6145
6146   /* signed is a little bit more difficult */
6147
6148   /* now sign adjust for both left & right */
6149
6150   /* modulus: sign of the right operand has no influence on the result! */
6151   if (AOP_TYPE(right) == AOP_LIT)
6152     {
6153       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
6154
6155       if (!rUnsigned && val < 0)
6156         emitcode ("mov", "b,#0x%02x", -val);
6157       else
6158         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6159     }
6160   else /* not literal */
6161     {
6162       if (rUnsigned)
6163         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6164       else
6165         {
6166           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6167           lbl = newiTempLabel (NULL);
6168           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6169           emitcode ("cpl", "a");  /* 2's complement */
6170           emitcode ("inc", "a");
6171           emitLabel (lbl);
6172           emitcode ("mov", "b,a");
6173         }
6174     }
6175
6176   /* let's see what's needed: */
6177   /* apply negative sign during runtime */
6178   runtimeSign = FALSE;
6179   /* negative sign from literals */
6180   compiletimeSign = FALSE;
6181
6182   /* sign adjust left side */
6183   if (AOP_TYPE(left) == AOP_LIT)
6184     {
6185       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
6186
6187       if (!lUnsigned && val < 0)
6188         {
6189           compiletimeSign = TRUE; /* set sign flag */
6190           emitcode ("mov", "a,#0x%02x", -val);
6191         }
6192       else
6193         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6194     }
6195   else /* ! literal */
6196     {
6197       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6198
6199       if (!lUnsigned)
6200         {
6201           runtimeSign = TRUE;
6202           emitcode ("clr", "F0"); /* clear sign flag */
6203
6204           lbl = newiTempLabel (NULL);
6205           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6206           emitcode ("setb", "F0"); /* set sign flag */
6207           emitcode ("cpl", "a");   /* 2's complement */
6208           emitcode ("inc", "a");
6209           emitLabel (lbl);
6210         }
6211     }
6212
6213   /* now the modulus */
6214   emitcode ("nop", "; workaround for DS80C390 div bug.");
6215   emitcode ("div", "ab");
6216
6217   if (runtimeSign || compiletimeSign)
6218     {
6219       emitcode ("mov", "a,b");
6220       lbl = newiTempLabel (NULL);
6221       if (runtimeSign)
6222         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6223       emitcode ("cpl", "a"); /* lsb 2's complement */
6224       emitcode ("inc", "a");
6225       emitLabel (lbl);
6226
6227       _G.accInUse++;
6228       aopOp (result, ic, TRUE, FALSE);
6229       size = AOP_SIZE (result) - 1;
6230
6231       if (size > 0)
6232         {
6233           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6234              then the result will be in b, a */
6235           emitcode ("mov", "b,a"); /* 1 */
6236           /* msb is 0x00 or 0xff depending on the sign */
6237           if (runtimeSign)
6238             {
6239               emitcode ("mov",  "c,F0");
6240               emitcode ("subb", "a,acc");
6241               emitcode ("xch",  "a,b"); /* 2 */
6242               while (size--)
6243                 aopPut (result, "b", offset++); /* write msb's */
6244             }
6245           else /* compiletimeSign */
6246             while (size--)
6247               aopPut (result, "#0xff", offset++); /* write msb's */
6248         }
6249       aopPut (result, "a", 0); /* 3: write lsb */
6250     }
6251   else
6252     {
6253       _G.accInUse++;
6254       aopOp(result, ic, TRUE, FALSE);
6255       size = AOP_SIZE (result) - 1;
6256
6257       aopPut (result, "b", 0);
6258       while (size--)
6259         aopPut (result, zero, offset++);
6260     }
6261   _G.accInUse--;
6262   popB (pushedB);
6263 }
6264
6265 /*-----------------------------------------------------------------*/
6266 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6267 /*-----------------------------------------------------------------*/
6268 static void genModTwoByte (operand *left, operand *right,
6269                             operand *result, iCode *ic)
6270 {
6271         sym_link *retype = getSpec(operandType(right));
6272         sym_link *letype = getSpec(operandType(left));
6273         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6274         symbol *lbl;
6275
6276         /* load up MA with left */
6277         /* save EA bit in F1 */
6278         lbl = newiTempLabel(NULL);
6279         emitcode ("setb","F1");
6280         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6281         emitcode ("clr","F1");
6282         emitLabel (lbl);
6283
6284         if (!umult) {
6285                 lbl = newiTempLabel(NULL);
6286                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6287                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6288                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6289                 emitcode ("xch", "a,b");
6290                 emitcode ("cpl","a");
6291                 emitcode ("add", "a,#1");
6292                 emitcode ("xch", "a,b");
6293                 emitcode ("cpl", "a"); // msb
6294                 emitcode ("addc","a,#0");
6295                 emitLabel (lbl);
6296                 emitcode ("mov","ma,b");
6297                 emitcode ("mov","ma,a");
6298         } else {
6299                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6300                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6301         }
6302
6303         /* load up MB with right */
6304         if (!umult) {
6305                 if (AOP_TYPE(right) == AOP_LIT) {
6306                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6307                         if (val < 0) {
6308                                 val = -val;
6309                         }
6310                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6311                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6312                 } else {
6313                         lbl = newiTempLabel(NULL);
6314                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6315                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6316                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6317                         emitcode ("xch", "a,b");
6318                         emitcode ("cpl","a");
6319                         emitcode ("add", "a,#1");
6320                         emitcode ("xch", "a,b");
6321                         emitcode ("cpl", "a"); // msb
6322                         emitcode ("addc", "a,#0");
6323                         emitLabel (lbl);
6324                         emitcode ("mov","mb,b");
6325                         emitcode ("mov","mb,a");
6326                 }
6327         } else {
6328                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6329                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6330         }
6331
6332         /* wait for multiplication to finish */
6333         lbl = newiTempLabel(NULL);
6334         emitLabel (lbl);
6335         emitcode("mov","a,mcnt1");
6336         emitcode("anl","a,#!constbyte",0x80);
6337         emitcode("jnz","!tlabel",lbl->key+100);
6338
6339         freeAsmop (left, NULL, ic, TRUE);
6340         freeAsmop (right, NULL, ic,TRUE);
6341         aopOp(result, ic, TRUE, FALSE);
6342
6343         aopPut(result,"mb",1);
6344         aopPut(result,"mb",0);
6345         freeAsmop (result, NULL, ic, TRUE);
6346
6347         /* restore EA bit in F1 */
6348         lbl = newiTempLabel(NULL);
6349         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6350         emitcode ("setb","EA");
6351         emitLabel (lbl);
6352 }
6353
6354 /*-----------------------------------------------------------------*/
6355 /* genMod - generates code for division                            */
6356 /*-----------------------------------------------------------------*/
6357 static void
6358 genMod (iCode * ic)
6359 {
6360   operand *left = IC_LEFT (ic);
6361   operand *right = IC_RIGHT (ic);
6362   operand *result = IC_RESULT (ic);
6363
6364   D (emitcode (";", "genMod"));
6365
6366   /* assign the asmops */
6367   AOP_OP_2 (ic);
6368
6369   /* special cases first */
6370   /* both are bits */
6371   if (AOP_TYPE (left) == AOP_CRY &&
6372       AOP_TYPE (right) == AOP_CRY)
6373     {
6374       genModbits (left, right, result, ic);
6375       goto release;
6376     }
6377
6378   /* if both are of size == 1 */
6379   if (AOP_SIZE (left) == 1 &&
6380       AOP_SIZE (right) == 1)
6381     {
6382       genModOneByte (left, right, result, ic);
6383       goto release;
6384     }
6385
6386   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6387           /* use the ds390 ARITHMETIC accel UNIT */
6388           genModTwoByte (left, right, result, ic);
6389           return ;
6390   }
6391
6392   /* should have been converted to function call */
6393   assert (0);
6394
6395 release:
6396   freeAsmop (result, NULL, ic, TRUE);
6397   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6398   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6399 }
6400
6401 /*-----------------------------------------------------------------*/
6402 /* genIfxJump :- will create a jump depending on the ifx           */
6403 /*-----------------------------------------------------------------*/
6404 static void
6405 genIfxJump (iCode * ic, char *jval, iCode *popIc)
6406 {
6407   symbol *jlbl;
6408   symbol *tlbl = newiTempLabel (NULL);
6409   char *inst;
6410
6411   /* if there is something to be popped then do it first */
6412   popForBranch (popIc, TRUE);
6413
6414   D (emitcode (";", "genIfxJump"));
6415
6416   /* if true label then we jump if condition
6417      supplied is true */
6418   if (IC_TRUE (ic))
6419     {
6420       jlbl = IC_TRUE (ic);
6421       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6422                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6423     }
6424   else
6425     {
6426       /* false label is present */
6427       jlbl = IC_FALSE (ic);
6428       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6429                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6430     }
6431   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6432     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6433   else
6434     emitcode (inst, "!tlabel", tlbl->key + 100);
6435   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6436   emitLabel (tlbl);
6437
6438   /* mark the icode as generated */
6439   ic->generated = 1;
6440 }
6441
6442 /*-----------------------------------------------------------------*/
6443 /* genCmp :- greater or less than comparison                       */
6444 /*-----------------------------------------------------------------*/
6445 static void
6446 genCmp (operand * left, operand * right,
6447         iCode * ic, iCode * ifx, int sign)
6448 {
6449   int size, offset = 0;
6450   unsigned long lit = 0L;
6451   operand *result;
6452
6453   D (emitcode (";", "genCmp"));
6454
6455   result = IC_RESULT (ic);
6456
6457   /* if left & right are bit variables */
6458   if (AOP_TYPE (left) == AOP_CRY &&
6459       AOP_TYPE (right) == AOP_CRY)
6460     {
6461       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6462       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6463     }
6464   else
6465     {
6466       /* subtract right from left if at the
6467          end the carry flag is set then we know that
6468          left is greater than right */
6469       size = max (AOP_SIZE (left), AOP_SIZE (right));
6470
6471       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6472       if ((size == 1) && !sign &&
6473           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6474         {
6475           symbol *lbl = newiTempLabel (NULL);
6476           emitcode ("cjne", "%s,%s,!tlabel",
6477                     aopGet (left, offset, FALSE, FALSE, NULL),
6478                     aopGet (right, offset, FALSE, FALSE, NULL),
6479                     lbl->key + 100);
6480           emitLabel (lbl);
6481         }
6482       else
6483         {
6484           if (AOP_TYPE (right) == AOP_LIT)
6485             {
6486               lit = ulFromVal (AOP (right)->aopu.aop_lit);
6487               /* optimize if(x < 0) or if(x >= 0) */
6488               if (lit == 0L)
6489                 {
6490                   if (!sign)
6491                     {
6492                       CLRC;
6493                     }
6494                   else
6495                     {
6496                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6497
6498                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6499                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6500
6501                       aopOp (result, ic, FALSE, FALSE);
6502
6503                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6504                         {
6505                           freeAsmop (result, NULL, ic, TRUE);
6506                           genIfxJump (ifx, "acc.7", ic->next);
6507                           return;
6508                         }
6509                       else
6510                         {
6511                           emitcode ("rlc", "a");
6512                         }
6513                       goto release_freedLR;
6514                     }
6515                   goto release;
6516                 }
6517             }
6518           CLRC;
6519           while (size--)
6520             {
6521               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6522               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6523               // emitcode (";", "genCmp #2");
6524               if (sign && (size == 0))
6525                 {
6526                   // emitcode (";", "genCmp #3");
6527                   emitcode ("xrl", "a,#!constbyte",0x80);
6528                   if (AOP_TYPE (right) == AOP_LIT)
6529                     {
6530                       unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
6531                       // emitcode (";", "genCmp #3.1");
6532                       emitcode ("subb", "a,#!constbyte",
6533                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6534                     }
6535                   else
6536                     {
6537                       // emitcode (";", "genCmp #3.2");
6538                       saveAccWarn = 0;
6539                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6540                       saveAccWarn = DEFAULT_ACC_WARNING;
6541                       emitcode ("xrl", "b,#!constbyte",0x80);
6542                       emitcode ("subb", "a,b");
6543                     }
6544                 }
6545               else
6546                 {
6547                   const char *s;
6548
6549                   // emitcode (";", "genCmp #4");
6550                   saveAccWarn = 0;
6551                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6552                   saveAccWarn = DEFAULT_ACC_WARNING;
6553
6554                   emitcode ("subb", "a,%s", s);
6555                 }
6556             }
6557         }
6558     }
6559
6560 release:
6561 /* Don't need the left & right operands any more; do need the result. */
6562   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6563   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6564
6565   aopOp (result, ic, FALSE, FALSE);
6566
6567 release_freedLR:
6568
6569   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6570     {
6571       outBitC (result);
6572     }
6573   else
6574     {
6575       /* if the result is used in the next
6576          ifx conditional branch then generate
6577          code a little differently */
6578       if (ifx)
6579         {
6580           genIfxJump (ifx, "c", ic->next);
6581         }
6582       else
6583         {
6584           outBitC (result);
6585         }
6586       /* leave the result in acc */
6587     }
6588   freeAsmop (result, NULL, ic, TRUE);
6589 }
6590
6591 /*-----------------------------------------------------------------*/
6592 /* genCmpGt :- greater than comparison                             */
6593 /*-----------------------------------------------------------------*/
6594 static void
6595 genCmpGt (iCode * ic, iCode * ifx)
6596 {
6597   operand *left, *right;
6598   sym_link *letype, *retype;
6599   int sign;
6600
6601   D (emitcode (";", "genCmpGt"));
6602
6603   left = IC_LEFT (ic);
6604   right = IC_RIGHT (ic);
6605
6606   letype = getSpec (operandType (left));
6607   retype = getSpec (operandType (right));
6608   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6609
6610   /* assign the left & right amsops */
6611   AOP_OP_2 (ic);
6612
6613   genCmp (right, left, ic, ifx, sign);
6614 }
6615
6616 /*-----------------------------------------------------------------*/
6617 /* genCmpLt - less than comparisons                                */
6618 /*-----------------------------------------------------------------*/
6619 static void
6620 genCmpLt (iCode * ic, iCode * ifx)
6621 {
6622   operand *left, *right;
6623   sym_link *letype, *retype;
6624   int sign;
6625
6626   D (emitcode (";", "genCmpLt"));
6627
6628   left = IC_LEFT (ic);
6629   right = IC_RIGHT (ic);
6630
6631   letype = getSpec (operandType (left));
6632   retype = getSpec (operandType (right));
6633   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6634
6635   /* assign the left & right amsops */
6636   AOP_OP_2 (ic);
6637
6638   genCmp (left, right, ic, ifx, sign);
6639 }
6640
6641 /*-----------------------------------------------------------------*/
6642 /* gencjneshort - compare and jump if not equal                    */
6643 /*-----------------------------------------------------------------*/
6644 static void
6645 gencjneshort (operand * left, operand * right, symbol * lbl)
6646 {
6647   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6648   int offset = 0;
6649   unsigned long lit = 0L;
6650
6651   D (emitcode (";", "gencjneshort"));
6652
6653   /* if the left side is a literal or
6654      if the right is in a pointer register and left
6655      is not */
6656   if ((AOP_TYPE (left) == AOP_LIT)  ||
6657       (AOP_TYPE (left) == AOP_IMMD) ||
6658       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6659     {
6660       operand *t = right;
6661       right = left;
6662       left = t;
6663     }
6664
6665   if (AOP_TYPE (right) == AOP_LIT)
6666     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6667
6668   if (opIsGptr (left) || opIsGptr (right))
6669     {
6670       /* We are comparing a generic pointer to something.
6671        * Exclude the generic type byte from the comparison.
6672        */
6673       size--;
6674       D (emitcode (";", "cjneshort: generic ptr special case."););
6675     }
6676
6677
6678   /* if the right side is a literal then anything goes */
6679   if (AOP_TYPE (right) == AOP_LIT &&
6680       AOP_TYPE (left) != AOP_DIR)
6681     {
6682       while (size--)
6683         {
6684           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6685           emitcode ("cjne", "a,%s,!tlabel",
6686                     aopGet (right, offset, FALSE, FALSE, NULL),
6687                     lbl->key + 100);
6688           offset++;
6689         }
6690     }
6691
6692   /* if the right side is in a register or in direct space or
6693      if the left is a pointer register & right is not */
6694   else if (AOP_TYPE (right) == AOP_REG ||
6695            AOP_TYPE (right) == AOP_DIR ||
6696            AOP_TYPE (right) == AOP_LIT ||
6697            AOP_TYPE (right) == AOP_IMMD ||
6698            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6699            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6700     {
6701       while (size--)
6702         {
6703           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6704           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6705               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6706             emitcode ("jnz", "!tlabel", lbl->key + 100);
6707           else
6708             emitcode ("cjne", "a,%s,!tlabel",
6709                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6710                       lbl->key + 100);
6711           offset++;
6712         }
6713     }
6714   else
6715     {
6716       /* right is a pointer reg need both a & b */
6717       while (size--)
6718         {
6719           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6720           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6721           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6722           offset++;
6723         }
6724     }
6725 }
6726
6727 /*-----------------------------------------------------------------*/
6728 /* gencjne - compare and jump if not equal                         */
6729 /*-----------------------------------------------------------------*/
6730 static void
6731 gencjne (operand * left, operand * right, symbol * lbl)
6732 {
6733   symbol *tlbl = newiTempLabel (NULL);
6734
6735   D (emitcode (";", "gencjne"));
6736
6737   gencjneshort (left, right, lbl);
6738
6739   emitcode ("mov", "a,%s", one);
6740   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6741   emitLabel (lbl);
6742   emitcode ("clr", "a");
6743   emitLabel (tlbl);
6744 }
6745
6746 /*-----------------------------------------------------------------*/
6747 /* genCmpEq - generates code for equal to                          */
6748 /*-----------------------------------------------------------------*/
6749 static void
6750 genCmpEq (iCode * ic, iCode * ifx)
6751 {
6752   operand *left, *right, *result;
6753   iCode * popIc = ic->next;
6754
6755   D (emitcode (";", "genCmpEq"));
6756
6757   AOP_OP_2 (ic);
6758   AOP_SET_LOCALS (ic);
6759
6760   /* if literal, literal on the right or
6761      if the right is in a pointer register and left
6762      is not */
6763   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6764       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6765     {
6766       operand *t = IC_RIGHT (ic);
6767       IC_RIGHT (ic) = IC_LEFT (ic);
6768       IC_LEFT (ic) = t;
6769     }
6770
6771   if (ifx &&                    /* !AOP_SIZE(result) */
6772       OP_SYMBOL (result) &&
6773       OP_SYMBOL (result)->regType == REG_CND)
6774     {
6775       symbol *tlbl;
6776       /* if they are both bit variables */
6777       if (AOP_TYPE (left) == AOP_CRY &&
6778           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6779         {
6780           if (AOP_TYPE (right) == AOP_LIT)
6781             {
6782               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6783               if (lit == 0L)
6784                 {
6785                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6786                   emitcode ("cpl", "c");
6787                 }
6788               else if (lit == 1L)
6789                 {
6790                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6791                 }
6792               else
6793                 {
6794                   emitcode ("clr", "c");
6795                 }
6796               /* AOP_TYPE(right) == AOP_CRY */
6797             }
6798           else
6799             {
6800               symbol *lbl = newiTempLabel (NULL);
6801               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6802               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6803               emitcode ("cpl", "c");
6804               emitLabel (lbl);
6805             }
6806           /* if true label then we jump if condition
6807              supplied is true */
6808           tlbl = newiTempLabel (NULL);
6809           if (IC_TRUE (ifx))
6810             {
6811               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6812               popForBranch (popIc, FALSE);
6813               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6814             }
6815           else
6816             {
6817               emitcode ("jc", "!tlabel", tlbl->key + 100);
6818               popForBranch (popIc, FALSE);
6819               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6820             }
6821           emitLabel (tlbl);
6822         }
6823       else
6824         {
6825           tlbl = newiTempLabel (NULL);
6826           gencjneshort (left, right, tlbl);
6827           if (IC_TRUE (ifx))
6828             {
6829               popForBranch (popIc, FALSE);
6830               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6831               emitLabel (tlbl);
6832             }
6833           else
6834             {
6835               symbol *lbl = newiTempLabel (NULL);
6836               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6837               emitLabel (tlbl);
6838               popForBranch (popIc, FALSE);
6839               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6840               emitLabel (lbl);
6841             }
6842         }
6843       /* mark the icode as generated */
6844       ifx->generated = 1;
6845
6846       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6847       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6848       return;
6849     }
6850
6851   /* if they are both bit variables */
6852   if (AOP_TYPE (left) == AOP_CRY &&
6853       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6854     {
6855       if (AOP_TYPE (right) == AOP_LIT)
6856         {
6857           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6858           if (lit == 0L)
6859             {
6860               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6861               emitcode ("cpl", "c");
6862             }
6863           else if (lit == 1L)
6864             {
6865               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6866             }
6867           else
6868             {
6869               emitcode ("clr", "c");
6870             }
6871           /* AOP_TYPE(right) == AOP_CRY */
6872         }
6873       else
6874         {
6875           symbol *lbl = newiTempLabel (NULL);
6876           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6877           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6878           emitcode ("cpl", "c");
6879           emitLabel (lbl);
6880         }
6881
6882       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6883       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6884
6885       aopOp (result, ic, TRUE, FALSE);
6886
6887       /* c = 1 if egal */
6888       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6889         {
6890           outBitC (result);
6891           goto release;
6892         }
6893       if (ifx)
6894         {
6895           genIfxJump (ifx, "c", popIc);
6896           goto release;
6897         }
6898       /* if the result is used in an arithmetic operation
6899          then put the result in place */
6900       outBitC (result);
6901     }
6902   else
6903     {
6904       gencjne (left, right, newiTempLabel (NULL));
6905
6906       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6907       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6908
6909       aopOp (result, ic, TRUE, FALSE);
6910
6911       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6912         {
6913           aopPut (result, "a", 0);
6914           goto release;
6915         }
6916       if (ifx)
6917         {
6918           genIfxJump (ifx, "a", popIc);
6919           goto release;
6920         }
6921       /* if the result is used in an arithmetic operation
6922          then put the result in place */
6923       if (AOP_TYPE (result) != AOP_CRY)
6924         outAcc (result);
6925       /* leave the result in acc */
6926     }
6927
6928 release:
6929   freeAsmop (result, NULL, ic, TRUE);
6930 }
6931
6932 /*-----------------------------------------------------------------*/
6933 /* ifxForOp - returns the icode containing the ifx for operand     */
6934 /*-----------------------------------------------------------------*/
6935 static iCode *
6936 ifxForOp (operand * op, iCode * ic)
6937 {
6938   iCode *ifxIc;
6939
6940   /* if true symbol then needs to be assigned */
6941   if (IS_TRUE_SYMOP (op))
6942     return NULL;
6943
6944   /* if this has register type condition and
6945      while skipping ipop's (see bug 1509084),
6946      the next instruction is ifx with the same operand
6947      and live to of the operand is upto the ifx only then */
6948   for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
6949   if (ifxIc && ifxIc->op == IFX &&
6950       IC_COND (ifxIc)->key == op->key &&
6951       OP_SYMBOL (op)->liveTo <= ifxIc->seq)
6952     return ifxIc;
6953
6954   return NULL;
6955 }
6956
6957 /*-----------------------------------------------------------------*/
6958 /* hasInc - operand is incremented before any other use            */
6959 /*-----------------------------------------------------------------*/
6960 static iCode *
6961 hasInc (operand *op, iCode *ic, int osize)
6962 {
6963   sym_link *type = operandType(op);
6964   sym_link *retype = getSpec (type);
6965   iCode *lic = ic->next;
6966   int isize ;
6967
6968   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6969   if (!IS_SYMOP(op)) return NULL;
6970
6971   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6972   if (IS_AGGREGATE(type->next)) return NULL;
6973   if (osize != (isize = getSize(type->next))) return NULL;
6974
6975   while (lic)
6976     {
6977       /* if operand of the form op = op + <sizeof *op> */
6978       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6979           isOperandEqual(IC_RESULT(lic),op) &&
6980           isOperandLiteral(IC_RIGHT(lic)) &&
6981           operandLitValue(IC_RIGHT(lic)) == isize)
6982         {
6983           return lic;
6984         }
6985       /* if the operand used or deffed */
6986       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key)
6987         {
6988           return NULL;
6989         }
6990       /* if GOTO or IFX */
6991       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6992       lic = lic->next;
6993     }
6994   return NULL;
6995 }
6996
6997 /*-----------------------------------------------------------------*/
6998 /* genAndOp - for && operation                                     */
6999 /*-----------------------------------------------------------------*/
7000 static void
7001 genAndOp (iCode * ic)
7002 {
7003   operand *left, *right, *result;
7004   symbol *tlbl;
7005
7006   D (emitcode (";", "genAndOp"));
7007
7008   /* note here that && operations that are in an
7009      if statement are taken away by backPatchLabels
7010      only those used in arthmetic operations remain */
7011   AOP_OP_2 (ic);
7012   AOP_SET_LOCALS (ic);
7013
7014   /* if both are bit variables */
7015   if (AOP_TYPE (left) == AOP_CRY &&
7016       AOP_TYPE (right) == AOP_CRY)
7017     {
7018       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7019       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
7020       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7021       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7022
7023       aopOp (result,ic,FALSE, FALSE);
7024       outBitC (result);
7025     }
7026   else
7027     {
7028       tlbl = newiTempLabel (NULL);
7029       toBoolean (left);
7030       emitcode ("jz", "!tlabel", tlbl->key + 100);
7031       toBoolean (right);
7032       emitLabel (tlbl);
7033       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7034       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7035
7036       aopOp (result,ic,FALSE, FALSE);
7037       outBitAcc (result);
7038     }
7039
7040   freeAsmop (result, NULL, ic, TRUE);
7041 }
7042
7043
7044 /*-----------------------------------------------------------------*/
7045 /* genOrOp - for || operation                                      */
7046 /*-----------------------------------------------------------------*/
7047 static void
7048 genOrOp (iCode * ic)
7049 {
7050   operand *left, *right, *result;
7051   symbol *tlbl;
7052
7053   D (emitcode (";", "genOrOp"));
7054
7055   /* note here that || operations that are in an
7056      if statement are taken away by backPatchLabels
7057      only those used in arthmetic operations remain */
7058   AOP_OP_2 (ic);
7059   AOP_SET_LOCALS (ic);
7060
7061   /* if both are bit variables */
7062   if (AOP_TYPE (left) == AOP_CRY &&
7063       AOP_TYPE (right) == AOP_CRY)
7064     {
7065       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7066       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
7067       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7068       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7069
7070       aopOp (result,ic,FALSE, FALSE);
7071
7072       outBitC (result);
7073     }
7074   else
7075     {
7076       tlbl = newiTempLabel (NULL);
7077       toBoolean (left);
7078       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7079       toBoolean (right);
7080       emitLabel (tlbl);
7081       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7082       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7083
7084       aopOp (result,ic,FALSE, FALSE);
7085
7086       outBitAcc (result);
7087     }
7088
7089   freeAsmop (result, NULL, ic, TRUE);
7090 }
7091
7092 /*-----------------------------------------------------------------*/
7093 /* isLiteralBit - test if lit == 2^n                               */
7094 /*-----------------------------------------------------------------*/
7095 static int
7096 isLiteralBit (unsigned long lit)
7097 {
7098   unsigned long pw[32] =
7099   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7100    0x100L, 0x200L, 0x400L, 0x800L,
7101    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7102    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7103    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7104    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7105    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7106   int idx;
7107
7108   for (idx = 0; idx < 32; idx++)
7109     if (lit == pw[idx])
7110       return idx + 1;
7111   return 0;
7112 }
7113
7114 /*-----------------------------------------------------------------*/
7115 /* continueIfTrue -                                                */
7116 /*-----------------------------------------------------------------*/
7117 static void
7118 continueIfTrue (iCode * ic)
7119 {
7120   if (IC_TRUE (ic))
7121     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7122   ic->generated = 1;
7123 }
7124
7125 /*-----------------------------------------------------------------*/
7126 /* jmpIfTrue -                                                     */
7127 /*-----------------------------------------------------------------*/
7128 static void
7129 jumpIfTrue (iCode * ic)
7130 {
7131   if (!IC_TRUE (ic))
7132     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7133   ic->generated = 1;
7134 }
7135
7136 /*-----------------------------------------------------------------*/
7137 /* jmpTrueOrFalse -                                                */
7138 /*-----------------------------------------------------------------*/
7139 static void
7140 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7141 {
7142   // ugly but optimized by peephole
7143   if (IC_TRUE (ic))
7144     {
7145       symbol *nlbl = newiTempLabel (NULL);
7146       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7147       emitLabel (tlbl);
7148       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7149       emitLabel (nlbl);
7150     }
7151   else
7152     {
7153       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7154       emitLabel (tlbl);
7155     }
7156   ic->generated = 1;
7157 }
7158
7159 // Generate code to perform a bit-wise logic operation
7160 // on two operands in far space (assumed to already have been
7161 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7162 // in far space. This requires pushing the result on the stack
7163 // then popping it into the result.
7164 static void
7165 genFarFarLogicOp(iCode *ic, char *logicOp)
7166 {
7167       int size, resultSize, compSize;
7168       int offset = 0;
7169
7170       TR_AP("#5");
7171       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7172       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7173                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7174
7175       _startLazyDPSEvaluation();
7176       for (size = compSize; (size--); offset++)
7177       {
7178           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7179           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7180           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7181
7182           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7183           emitcode ("push", "acc");
7184       }
7185       _endLazyDPSEvaluation();
7186
7187       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7188       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7189       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7190
7191       resultSize = AOP_SIZE(IC_RESULT(ic));
7192
7193       ADJUST_PUSHED_RESULT(compSize, resultSize);
7194
7195       _startLazyDPSEvaluation();
7196       while (compSize--)
7197       {
7198           emitcode ("pop", "acc");
7199           aopPut (IC_RESULT (ic), "a", compSize);
7200       }
7201       _endLazyDPSEvaluation();
7202       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7203 }
7204
7205
7206 /*-----------------------------------------------------------------*/
7207 /* genAnd  - code for and                                          */
7208 /*-----------------------------------------------------------------*/
7209 static void
7210 genAnd (iCode * ic, iCode * ifx)
7211 {
7212   operand *left, *right, *result;
7213   int size, offset = 0;
7214   unsigned long lit = 0L;
7215   int bytelit = 0;
7216   char buffer[10];
7217   bool pushResult;
7218
7219   D (emitcode (";", "genAnd"));
7220
7221   AOP_OP_3_NOFATAL (ic, pushResult);
7222   AOP_SET_LOCALS (ic);
7223
7224   if (pushResult)
7225   {
7226       genFarFarLogicOp(ic, "anl");
7227       return;
7228   }
7229
7230 #ifdef DEBUG_TYPE
7231   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7232             AOP_TYPE (result),
7233             AOP_TYPE (left), AOP_TYPE (right));
7234   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7235             AOP_SIZE (result),
7236             AOP_SIZE (left), AOP_SIZE (right));
7237 #endif
7238
7239   /* if left is a literal & right is not then exchange them */
7240   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7241 #ifdef LOGIC_OPS_BROKEN
7242     ||  AOP_NEEDSACC (left)
7243 #endif
7244     )
7245     {
7246       operand *tmp = right;
7247       right = left;
7248       left = tmp;
7249     }
7250
7251   /* if result = right then exchange left and right */
7252   if (sameRegs (AOP (result), AOP (right)))
7253     {
7254       operand *tmp = right;
7255       right = left;
7256       left = tmp;
7257     }
7258
7259   /* if right is bit then exchange them */
7260   if (AOP_TYPE (right) == AOP_CRY &&
7261       AOP_TYPE (left) != AOP_CRY)
7262     {
7263       operand *tmp = right;
7264       right = left;
7265       left = tmp;
7266     }
7267   if (AOP_TYPE (right) == AOP_LIT)
7268     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7269
7270   size = AOP_SIZE (result);
7271
7272   // if(bit & yy)
7273   // result = bit & yy;
7274   if (AOP_TYPE (left) == AOP_CRY)
7275     {
7276       // c = bit & literal;
7277       if (AOP_TYPE (right) == AOP_LIT)
7278         {
7279           if (lit & 1)
7280             {
7281               if (size && sameRegs (AOP (result), AOP (left)))
7282                 // no change
7283                 goto release;
7284               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7285             }
7286           else
7287             {
7288               // bit(result) = 0;
7289               if (size && (AOP_TYPE (result) == AOP_CRY))
7290                 {
7291                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7292                   goto release;
7293                 }
7294               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7295                 {
7296                   jumpIfTrue (ifx);
7297                   goto release;
7298                 }
7299               emitcode ("clr", "c");
7300             }
7301         }
7302       else
7303         {
7304           if (AOP_TYPE (right) == AOP_CRY)
7305             {
7306               // c = bit & bit;
7307               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7308               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7309             }
7310           else
7311             {
7312               // c = bit & val;
7313               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7314               // c = lsb
7315               emitcode ("rrc", "a");
7316               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7317             }
7318         }
7319       // bit = c
7320       // val = c
7321       if (size)
7322         outBitC (result);
7323       // if(bit & ...)
7324       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7325         genIfxJump (ifx, "c", ic->next);
7326       goto release;
7327     }
7328
7329   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7330   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7331   if ((AOP_TYPE (right) == AOP_LIT) &&
7332       (AOP_TYPE (result) == AOP_CRY) &&
7333       (AOP_TYPE (left) != AOP_CRY))
7334     {
7335       int posbit = isLiteralBit (lit);
7336       /* left &  2^n */
7337       if (posbit)
7338         {
7339           posbit--;
7340           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7341           // bit = left & 2^n
7342           if (size)
7343             {
7344               switch (posbit & 0x07)
7345                 {
7346                   case 0: emitcode ("rrc", "a");
7347                           break;
7348                   case 7: emitcode ("rlc", "a");
7349                           break;
7350                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7351                           break;
7352                 }
7353             }
7354           // if(left &  2^n)
7355           else
7356             {
7357               if (ifx)
7358                 {
7359                   SNPRINTF (buffer, sizeof(buffer),
7360                             "acc.%d", posbit & 0x07);
7361                   genIfxJump (ifx, buffer, ic->next);
7362                 }
7363               else
7364                 {
7365                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7366                 }
7367               goto release;
7368             }
7369         }
7370       else
7371         {
7372           symbol *tlbl = newiTempLabel (NULL);
7373           int sizel = AOP_SIZE (left);
7374           if (size)
7375             emitcode ("setb", "c");
7376           while (sizel--)
7377             {
7378               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7379                 {
7380                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7381                   // byte ==  2^n ?
7382                   if ((posbit = isLiteralBit (bytelit)) != 0)
7383                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7384                   else
7385                     {
7386                       if (bytelit != 0x0FFL)
7387                         emitcode ("anl", "a,%s",
7388                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7389                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7390                     }
7391                 }
7392               offset++;
7393             }
7394           // bit = left & literal
7395           if (size)
7396             {
7397               emitcode ("clr", "c");
7398               emitLabel (tlbl);
7399             }
7400           // if(left & literal)
7401           else
7402             {
7403               if (ifx)
7404                 jmpTrueOrFalse (ifx, tlbl);
7405               else
7406                 emitLabel (tlbl);
7407               goto release;
7408             }
7409         }
7410       outBitC (result);
7411       goto release;
7412     }
7413
7414   /* if left is same as result */
7415   if (sameRegs (AOP (result), AOP (left)))
7416     {
7417       for (; size--; offset++)
7418         {
7419           if (AOP_TYPE (right) == AOP_LIT)
7420             {
7421               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7422               if (bytelit == 0x0FF)
7423                 {
7424                   /* dummy read of volatile operand */
7425                   if (isOperandVolatile (left, FALSE))
7426                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7427                   else
7428                     continue;
7429                 }
7430               else if (bytelit == 0)
7431                 {
7432                   aopPut (result, zero, offset);
7433                 }
7434               else if (IS_AOP_PREG (result))
7435                 {
7436                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7437                   emitcode ("anl", "a,%s",
7438                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7439                   aopPut (result, "a", offset);
7440                 }
7441               else
7442                 emitcode ("anl", "%s,%s",
7443                           aopGet (left, offset, FALSE, TRUE, NULL),
7444                           aopGet (right, offset, FALSE, FALSE, NULL));
7445             }
7446           else
7447             {
7448               if (AOP_TYPE (left) == AOP_ACC)
7449                 {
7450                   if (offset)
7451                     emitcode("mov", "a,b");
7452                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7453                 }
7454               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7455                 {
7456                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7457                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7458                   emitcode ("anl", "a,b");
7459                   aopPut (result, "a", offset);
7460                 }
7461               else if (aopGetUsesAcc (left, offset))
7462                 {
7463                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7464                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7465                   aopPut (result, "a", offset);
7466                 }
7467               else
7468                 {
7469                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7470                   if (IS_AOP_PREG (result))
7471                     {
7472                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7473                       aopPut (result, "a", offset);
7474                     }
7475                   else
7476                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7477                 }
7478             }
7479         }
7480     }
7481   else
7482     {
7483       // left & result in different registers
7484       if (AOP_TYPE (result) == AOP_CRY)
7485         {
7486           // result = bit
7487           // if(size), result in bit
7488           // if(!size && ifx), conditional oper: if(left & right)
7489           symbol *tlbl = newiTempLabel (NULL);
7490           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7491           if (size)
7492             emitcode ("setb", "c");
7493           while (sizer--)
7494             {
7495               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7496                   && AOP_TYPE(left)==AOP_ACC)
7497                 {
7498                   if (offset)
7499                     emitcode("mov", "a,b");
7500                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7501                 }
7502               else if (AOP_TYPE(left)==AOP_ACC)
7503                 {
7504                   if (!offset)
7505                     {
7506                       bool pushedB = pushB ();
7507                       emitcode("mov", "b,a");
7508                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7509                       emitcode("anl", "a,b");
7510                       popB (pushedB);
7511                     }
7512                   else
7513                     {
7514                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7515                       emitcode("anl", "a,b");
7516                     }
7517                 }
7518               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7519                 {
7520                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7521                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7522                   emitcode ("anl", "a,b");
7523                 }
7524               else if (aopGetUsesAcc (left, offset))
7525                 {
7526                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7527                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7528                 }
7529               else
7530                 {
7531                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7532                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7533                 }
7534
7535               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7536               offset++;
7537             }
7538           if (size)
7539             {
7540               CLRC;
7541               emitLabel (tlbl);
7542               outBitC (result);
7543             }
7544           else if (ifx)
7545             jmpTrueOrFalse (ifx, tlbl);
7546           else
7547             emitLabel (tlbl);
7548         }
7549       else
7550         {
7551           for (; (size--); offset++)
7552             {
7553               // normal case
7554               // result = left & right
7555               if (AOP_TYPE (right) == AOP_LIT)
7556                 {
7557                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7558                   if (bytelit == 0x0FF)
7559                     {
7560                       aopPut (result,
7561                               aopGet (left, offset, FALSE, FALSE, NULL),
7562                               offset);
7563                       continue;
7564                     }
7565                   else if (bytelit == 0)
7566                     {
7567                       /* dummy read of volatile operand */
7568                       if (isOperandVolatile (left, FALSE))
7569                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7570                       aopPut (result, zero, offset);
7571                       continue;
7572                     }
7573                   else if (AOP_TYPE (left) == AOP_ACC)
7574                     {
7575                       if (!offset)
7576                         {
7577                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7578                           aopPut (result, "a", offset);
7579                           continue;
7580                         }
7581                       else
7582                         {
7583                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7584                           aopPut (result, "b", offset);
7585                           continue;
7586                         }
7587                     }
7588                 }
7589               // faster than result <- left, anl result,right
7590               // and better if result is SFR
7591               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7592                   && AOP_TYPE(left)==AOP_ACC)
7593                 {
7594                   if (offset)
7595                     emitcode("mov", "a,b");
7596                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7597                 }
7598               else if (AOP_TYPE(left)==AOP_ACC)
7599                 {
7600                   if (!offset)
7601                     {
7602                       bool pushedB = pushB ();
7603                       emitcode("mov", "b,a");
7604                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7605                       emitcode("anl", "a,b");
7606                       popB (pushedB);
7607                     }
7608                   else
7609                     {
7610                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7611                       emitcode("anl", "a,b");
7612                     }
7613                 }
7614               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7615                 {
7616                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7617                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7618                   emitcode ("anl", "a,b");
7619                 }
7620               else if (aopGetUsesAcc (left, offset))
7621                 {
7622                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7623                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7624                 }
7625               else
7626                 {
7627                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7628                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7629                 }
7630               aopPut (result, "a", offset);
7631             }
7632         }
7633     }
7634
7635 release:
7636   freeAsmop (result, NULL, ic, TRUE);
7637   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7638   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7639 }
7640
7641 /*-----------------------------------------------------------------*/
7642 /* genOr  - code for or                                            */
7643 /*-----------------------------------------------------------------*/
7644 static void
7645 genOr (iCode * ic, iCode * ifx)
7646 {
7647   operand *left, *right, *result;
7648   int size, offset = 0;
7649   unsigned long lit = 0L;
7650   int bytelit = 0;
7651   bool     pushResult;
7652
7653   D (emitcode (";", "genOr"));
7654
7655   AOP_OP_3_NOFATAL (ic, pushResult);
7656   AOP_SET_LOCALS (ic);
7657
7658   if (pushResult)
7659   {
7660       genFarFarLogicOp(ic, "orl");
7661       return;
7662   }
7663
7664
7665 #ifdef DEBUG_TYPE
7666   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7667             AOP_TYPE (result),
7668             AOP_TYPE (left), AOP_TYPE (right));
7669   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7670             AOP_SIZE (result),
7671             AOP_SIZE (left), AOP_SIZE (right));
7672 #endif
7673
7674   /* if left is a literal & right is not then exchange them */
7675   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7676 #ifdef LOGIC_OPS_BROKEN
7677    || AOP_NEEDSACC (left) // I think this is a net loss now.
7678 #endif
7679       )
7680     {
7681       operand *tmp = right;
7682       right = left;
7683       left = tmp;
7684     }
7685
7686   /* if result = right then exchange them */
7687   if (sameRegs (AOP (result), AOP (right)))
7688     {
7689       operand *tmp = right;
7690       right = left;
7691       left = tmp;
7692     }
7693
7694   /* if right is bit then exchange them */
7695   if (AOP_TYPE (right) == AOP_CRY &&
7696       AOP_TYPE (left) != AOP_CRY)
7697     {
7698       operand *tmp = right;
7699       right = left;
7700       left = tmp;
7701     }
7702   if (AOP_TYPE (right) == AOP_LIT)
7703     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7704
7705   size = AOP_SIZE (result);
7706
7707   // if(bit | yy)
7708   // xx = bit | yy;
7709   if (AOP_TYPE (left) == AOP_CRY)
7710     {
7711       if (AOP_TYPE (right) == AOP_LIT)
7712         {
7713           // c = bit | literal;
7714           if (lit)
7715             {
7716               // lit != 0 => result = 1
7717               if (AOP_TYPE (result) == AOP_CRY)
7718                 {
7719                   if (size)
7720                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7721                   else if (ifx)
7722                     continueIfTrue (ifx);
7723                   goto release;
7724                 }
7725               emitcode ("setb", "c");
7726             }
7727           else
7728             {
7729               // lit == 0 => result = left
7730               if (size && sameRegs (AOP (result), AOP (left)))
7731                 goto release;
7732               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7733             }
7734         }
7735       else
7736         {
7737           if (AOP_TYPE (right) == AOP_CRY)
7738             {
7739               // c = bit | bit;
7740               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7741               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7742             }
7743           else
7744             {
7745               // c = bit | val;
7746               symbol *tlbl = newiTempLabel (NULL);
7747               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7748                 emitcode ("setb", "c");
7749               emitcode ("jb", "%s,!tlabel",
7750                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7751               toBoolean (right);
7752               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7753               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7754                 {
7755                   jmpTrueOrFalse (ifx, tlbl);
7756                   goto release;
7757                 }
7758               else
7759                 {
7760                   CLRC;
7761                   emitLabel (tlbl);
7762                 }
7763             }
7764         }
7765       // bit = c
7766       // val = c
7767       if (size)
7768         outBitC (result);
7769       // if(bit | ...)
7770       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7771         genIfxJump (ifx, "c", ic->next);
7772       goto release;
7773     }
7774
7775   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7776   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7777   if ((AOP_TYPE (right) == AOP_LIT) &&
7778       (AOP_TYPE (result) == AOP_CRY) &&
7779       (AOP_TYPE (left) != AOP_CRY))
7780     {
7781       if (lit)
7782         {
7783           // result = 1
7784           if (size)
7785             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7786           else
7787             continueIfTrue (ifx);
7788           goto release;
7789         }
7790       else
7791         {
7792           // lit = 0, result = boolean(left)
7793           if (size)
7794             emitcode ("setb", "c");
7795           toBoolean (right);
7796           if (size)
7797             {
7798               symbol *tlbl = newiTempLabel (NULL);
7799               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7800               CLRC;
7801               emitLabel (tlbl);
7802             }
7803           else
7804             {
7805               genIfxJump (ifx, "a", ic->next);
7806               goto release;
7807             }
7808         }
7809       outBitC (result);
7810       goto release;
7811     }
7812
7813   /* if left is same as result */
7814   if (sameRegs (AOP (result), AOP (left)))
7815     {
7816       for (; size--; offset++)
7817         {
7818           if (AOP_TYPE (right) == AOP_LIT)
7819             {
7820               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7821               if (bytelit == 0)
7822                 {
7823                   /* dummy read of volatile operand */
7824                   if (isOperandVolatile (left, FALSE))
7825                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7826                   else
7827                     continue;
7828                 }
7829               else if (bytelit == 0x0FF)
7830                 {
7831                   aopPut (result, "#0xFF", offset);
7832                 }
7833               else if (IS_AOP_PREG (left))
7834                 {
7835                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7836                   emitcode ("orl", "a,%s",
7837                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7838                   aopPut (result, "a", offset);
7839                 }
7840               else
7841                 {
7842                   emitcode ("orl", "%s,%s",
7843                             aopGet (left, offset, FALSE, TRUE, NULL),
7844                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7845                 }
7846             }
7847           else
7848             {
7849               if (AOP_TYPE (left) == AOP_ACC)
7850                 {
7851                   if (offset)
7852                     emitcode("mov", "a,b");
7853                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7854                 }
7855               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7856                 {
7857                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7858                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7859                   emitcode ("orl", "a,b");
7860                   aopPut (result, "a", offset);
7861                 }
7862               else if (aopGetUsesAcc (left, offset))
7863                 {
7864                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7865                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7866                   aopPut (result, "a", offset);
7867                 }
7868               else
7869                 {
7870                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7871                   if (IS_AOP_PREG (left))
7872                     {
7873                       emitcode ("orl", "a,%s",
7874                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7875                       aopPut (result, "a", offset);
7876                     }
7877                   else
7878                     {
7879                       emitcode ("orl", "%s,a",
7880                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7881                     }
7882                 }
7883             }
7884         }
7885     }
7886   else
7887     {
7888       // left & result in different registers
7889       if (AOP_TYPE (result) == AOP_CRY)
7890         {
7891           // result = bit
7892           // if(size), result in bit
7893           // if(!size && ifx), conditional oper: if(left | right)
7894           symbol *tlbl = newiTempLabel (NULL);
7895           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7896           if (size)
7897             emitcode ("setb", "c");
7898           while (sizer--)
7899             {
7900               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7901                   && AOP_TYPE(left)==AOP_ACC)
7902                 {
7903                   if (offset)
7904                     emitcode("mov", "a,b");
7905                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7906                 }
7907               else if (AOP_TYPE(left)==AOP_ACC)
7908                 {
7909                   if (!offset)
7910                     {
7911                       bool pushedB = pushB ();
7912                       emitcode("mov", "b,a");
7913                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7914                       emitcode("orl", "a,b");
7915                       popB (pushedB);
7916                     }
7917                   else
7918                     {
7919                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7920                       emitcode("orl", "a,b");
7921                     }
7922                 }
7923               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7924                 {
7925                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7926                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7927                   emitcode ("orl", "a,b");
7928                 }
7929               else if (aopGetUsesAcc (left, offset))
7930                 {
7931                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7932                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7933                 }
7934               else
7935                 {
7936                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7937                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7938               }
7939
7940               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7941               offset++;
7942             }
7943           if (size)
7944             {
7945               CLRC;
7946               emitLabel (tlbl);
7947               outBitC (result);
7948             }
7949           else if (ifx)
7950             jmpTrueOrFalse (ifx, tlbl);
7951           else
7952             emitLabel (tlbl);
7953         }
7954       else
7955         {
7956             _startLazyDPSEvaluation();
7957           for (; (size--); offset++)
7958             {
7959               // normal case
7960               // result = left | right
7961               if (AOP_TYPE (right) == AOP_LIT)
7962                 {
7963                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7964                   if (bytelit == 0)
7965                     {
7966                       aopPut (result,
7967                               aopGet (left, offset, FALSE, FALSE, NULL),
7968                               offset);
7969                       continue;
7970                     }
7971                   else if (bytelit == 0x0FF)
7972                     {
7973                       /* dummy read of volatile operand */
7974                       if (isOperandVolatile (left, FALSE))
7975                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7976                       aopPut (result, "#0xFF", offset);
7977                       continue;
7978                     }
7979                 }
7980               // faster than result <- left, orl result,right
7981               // and better if result is SFR
7982               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7983                   && AOP_TYPE(left)==AOP_ACC)
7984                 {
7985                   if (offset)
7986                     emitcode("mov", "a,b");
7987                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7988                 }
7989               else if (AOP_TYPE(left)==AOP_ACC)
7990                 {
7991                   if (!offset)
7992                     {
7993                       bool pushedB = pushB ();
7994                       emitcode("mov", "b,a");
7995                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7996                       emitcode("orl", "a,b");
7997                       popB (pushedB);
7998                     }
7999                   else
8000                     {
8001                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8002                       emitcode("orl", "a,b");
8003                     }
8004                 }
8005               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8006                 {
8007                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8008                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8009                   emitcode ("orl", "a,b");
8010                 }
8011               else if (aopGetUsesAcc (left, offset))
8012                 {
8013                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8014                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8015                 }
8016               else
8017                 {
8018                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8019                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
8020                 }
8021               aopPut (result, "a", offset);
8022             }
8023             _endLazyDPSEvaluation();
8024         }
8025     }
8026
8027 release:
8028   freeAsmop (result, NULL, ic, TRUE);
8029   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8030   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8031 }
8032
8033 /*-----------------------------------------------------------------*/
8034 /* genXor - code for xclusive or                                   */
8035 /*-----------------------------------------------------------------*/
8036 static void
8037 genXor (iCode * ic, iCode * ifx)
8038 {
8039   operand *left, *right, *result;
8040   int size, offset = 0;
8041   unsigned long lit = 0L;
8042   int bytelit = 0;
8043   bool pushResult;
8044
8045   D (emitcode (";", "genXor"));
8046
8047   AOP_OP_3_NOFATAL (ic, pushResult);
8048   AOP_SET_LOCALS (ic);
8049
8050   if (pushResult)
8051   {
8052       genFarFarLogicOp(ic, "xrl");
8053       return;
8054   }
8055
8056 #ifdef DEBUG_TYPE
8057   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
8058             AOP_TYPE (result),
8059             AOP_TYPE (left), AOP_TYPE (right));
8060   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
8061             AOP_SIZE (result),
8062             AOP_SIZE (left), AOP_SIZE (right));
8063 #endif
8064
8065   /* if left is a literal & right is not ||
8066      if left needs acc & right does not */
8067   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
8068 #ifdef LOGIC_OPS_BROKEN
8069       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
8070 #endif
8071      )
8072     {
8073       operand *tmp = right;
8074       right = left;
8075       left = tmp;
8076     }
8077
8078   /* if result = right then exchange them */
8079   if (sameRegs (AOP (result), AOP (right)))
8080     {
8081       operand *tmp = right;
8082       right = left;
8083       left = tmp;
8084     }
8085
8086   /* if right is bit then exchange them */
8087   if (AOP_TYPE (right) == AOP_CRY &&
8088       AOP_TYPE (left) != AOP_CRY)
8089     {
8090       operand *tmp = right;
8091       right = left;
8092       left = tmp;
8093     }
8094
8095   if (AOP_TYPE (right) == AOP_LIT)
8096     lit = ulFromVal (AOP (right)->aopu.aop_lit);
8097
8098   size = AOP_SIZE (result);
8099
8100   // if(bit ^ yy)
8101   // xx = bit ^ yy;
8102   if (AOP_TYPE (left) == AOP_CRY)
8103     {
8104       if (AOP_TYPE (right) == AOP_LIT)
8105         {
8106           // c = bit & literal;
8107           if (lit >> 1)
8108             {
8109               // lit>>1  != 0 => result = 1
8110               if (AOP_TYPE (result) == AOP_CRY)
8111                 {
8112                   if (size)
8113                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8114                   else if (ifx)
8115                     continueIfTrue (ifx);
8116                   goto release;
8117                 }
8118               emitcode ("setb", "c");
8119             }
8120           else
8121             {
8122               // lit == (0 or 1)
8123               if (lit == 0)
8124                 {
8125                   // lit == 0, result = left
8126                   if (size && sameRegs (AOP (result), AOP (left)))
8127                     goto release;
8128                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8129                 }
8130               else
8131                 {
8132                   // lit == 1, result = not(left)
8133                   if (size && sameRegs (AOP (result), AOP (left)))
8134                     {
8135                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8136                       goto release;
8137                     }
8138                   else
8139                     {
8140                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8141                       emitcode ("cpl", "c");
8142                     }
8143                 }
8144             }
8145         }
8146       else
8147         {
8148           // right != literal
8149           symbol *tlbl = newiTempLabel (NULL);
8150           if (AOP_TYPE (right) == AOP_CRY)
8151             {
8152               // c = bit ^ bit;
8153               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8154             }
8155           else
8156             {
8157               int sizer = AOP_SIZE (right);
8158               // c = bit ^ val
8159               // if val>>1 != 0, result = 1
8160               emitcode ("setb", "c");
8161               while (sizer)
8162                 {
8163                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8164                   if (sizer == 1)
8165                     // test the msb of the lsb
8166                     emitcode ("anl", "a,#!constbyte",0xfe);
8167                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8168                   sizer--;
8169                 }
8170               // val = (0,1)
8171               emitcode ("rrc", "a");
8172             }
8173           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8174           emitcode ("cpl", "c");
8175           emitLabel (tlbl);
8176         }
8177       // bit = c
8178       // val = c
8179       if (size)
8180         outBitC (result);
8181       // if(bit ^ ...)
8182       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8183         genIfxJump (ifx, "c", ic->next);
8184       goto release;
8185     }
8186
8187   /* if left is same as result */
8188   if (sameRegs (AOP (result), AOP (left)))
8189     {
8190       for (; size--; offset++)
8191         {
8192           if (AOP_TYPE (right) == AOP_LIT)
8193             {
8194               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8195               if (bytelit == 0)
8196                 {
8197                   /* dummy read of volatile operand */
8198                   if (isOperandVolatile (left, FALSE))
8199                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8200                   else
8201                     continue;
8202                 }
8203               else if (IS_AOP_PREG (left))
8204                 {
8205                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8206                   emitcode ("xrl", "a,%s",
8207                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8208                   aopPut (result, "a", offset);
8209                 }
8210               else
8211                 {
8212                   emitcode ("xrl", "%s,%s",
8213                             aopGet (left, offset, FALSE, TRUE, NULL),
8214                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8215                 }
8216             }
8217           else
8218             {
8219               if (AOP_TYPE (left) == AOP_ACC)
8220                 {
8221                   if (offset)
8222                     emitcode("mov", "a,b");
8223                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8224                 }
8225               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8226                 {
8227                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8228                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8229                   emitcode ("xrl", "a,b");
8230                   aopPut (result, "a", offset);
8231                 }
8232               else if (aopGetUsesAcc (left, offset))
8233                 {
8234                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8235                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8236                   aopPut (result, "a", offset);
8237                 }
8238               else
8239                 {
8240                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8241                   if (IS_AOP_PREG (left))
8242                     {
8243                       emitcode ("xrl", "a,%s",
8244                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8245                       aopPut (result, "a", offset);
8246                     }
8247                   else
8248                     emitcode ("xrl", "%s,a",
8249                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8250                 }
8251             }
8252         }
8253     }
8254   else
8255     {
8256       // left & result in different registers
8257       if (AOP_TYPE (result) == AOP_CRY)
8258         {
8259           // result = bit
8260           // if(size), result in bit
8261           // if(!size && ifx), conditional oper: if(left ^ right)
8262           symbol *tlbl = newiTempLabel (NULL);
8263           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8264
8265           if (size)
8266             emitcode ("setb", "c");
8267           while (sizer--)
8268             {
8269               if ((AOP_TYPE (right) == AOP_LIT) &&
8270                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8271                 {
8272                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8273                 }
8274               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8275                   && AOP_TYPE(left)==AOP_ACC)
8276                 {
8277                   if (offset)
8278                     emitcode("mov", "a,b");
8279                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8280                 }
8281               else if (AOP_TYPE(left)==AOP_ACC)
8282                 {
8283                   if (!offset)
8284                     {
8285                       bool pushedB = pushB ();
8286                       emitcode("mov", "b,a");
8287                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8288                       emitcode("xrl", "a,b");
8289                       popB (pushedB);
8290                     }
8291                   else
8292                     {
8293                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8294                       emitcode("xrl", "a,b");
8295                     }
8296                 }
8297               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8298                 {
8299                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8300                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8301                   emitcode ("xrl", "a,b");
8302                 }
8303               else if (aopGetUsesAcc (left, offset))
8304                 {
8305                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8306                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8307                 }
8308               else
8309                 {
8310                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8311                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8312                 }
8313
8314               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8315               offset++;
8316             }
8317           if (size)
8318             {
8319               CLRC;
8320               emitLabel (tlbl);
8321               outBitC (result);
8322             }
8323           else if (ifx)
8324             jmpTrueOrFalse (ifx, tlbl);
8325         }
8326       else
8327         {
8328           for (; (size--); offset++)
8329             {
8330               // normal case
8331               // result = left ^ right
8332               if (AOP_TYPE (right) == AOP_LIT)
8333                 {
8334                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8335                   if (bytelit == 0)
8336                     {
8337                       aopPut (result,
8338                               aopGet (left, offset, FALSE, FALSE, NULL),
8339                               offset);
8340                       continue;
8341                     }
8342                   D (emitcode (";", "better literal XOR."));
8343                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8344                   emitcode ("xrl", "a, %s",
8345                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8346                 }
8347               else
8348                 {
8349                   // faster than result <- left, anl result,right
8350                   // and better if result is SFR
8351                   if (AOP_TYPE (left) == AOP_ACC)
8352                     {
8353                       emitcode ("xrl", "a,%s",
8354                                 aopGet (right, offset,
8355                                         FALSE, FALSE, DP2_RESULT_REG));
8356                     }
8357                   else
8358                     {
8359                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8360                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8361                         {
8362                           emitcode("mov", "b,a");
8363                           rOp = "b";
8364                         }
8365
8366                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8367                       emitcode ("xrl", "a,%s", rOp);
8368                     }
8369                 }
8370               aopPut (result, "a", offset);
8371             }
8372         }
8373     }
8374
8375 release:
8376   freeAsmop (result, NULL, ic, TRUE);
8377   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8378   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8379 }
8380
8381 /*-----------------------------------------------------------------*/
8382 /* genInline - write the inline code out                           */
8383 /*-----------------------------------------------------------------*/
8384 static void
8385 genInline (iCode * ic)
8386 {
8387   char *buffer, *bp, *bp1;
8388   bool inComment = FALSE;
8389
8390   D (emitcode (";", "genInline"));
8391
8392   _G.inLine += (!options.asmpeep);
8393
8394   buffer = bp = bp1 = Safe_strdup (IC_INLINE (ic));
8395
8396   /* emit each line as a code */
8397   while (*bp)
8398     {
8399       switch (*bp)
8400         {
8401         case ';':
8402           inComment = TRUE;
8403           ++bp;
8404           break;
8405
8406         case '\n':
8407           inComment = FALSE;
8408           *bp++ = '\0';
8409           emitcode (bp1, "");
8410           bp1 = bp;
8411           break;
8412
8413         default:
8414           /* Add \n for labels, not dirs such as c:\mydir */
8415           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8416             {
8417               ++bp;
8418               *bp = '\0';
8419               ++bp;
8420               emitcode (bp1, "");
8421               bp1 = bp;
8422             }
8423           else
8424             ++bp;
8425           break;
8426         }
8427     }
8428   if (bp1 != bp)
8429     emitcode (bp1, "");
8430
8431   Safe_free (buffer);
8432
8433   _G.inLine -= (!options.asmpeep);
8434 }
8435
8436 /*-----------------------------------------------------------------*/
8437 /* genRRC - rotate right with carry                                */
8438 /*-----------------------------------------------------------------*/
8439 static void
8440 genRRC (iCode * ic)
8441 {
8442   operand *left, *result;
8443   int     size, offset;
8444   char    *l;
8445
8446   D (emitcode (";", "genRRC"));
8447
8448   /* rotate right with carry */
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   /* move it to the result */
8455   size = AOP_SIZE (result);
8456   offset = size - 1;
8457   CLRC;
8458
8459   _startLazyDPSEvaluation ();
8460   while (size--)
8461     {
8462       l = aopGet (left, offset, FALSE, FALSE, NULL);
8463       MOVA (l);
8464       emitcode ("rrc", "a");
8465       if (AOP_SIZE (result) > 1)
8466         aopPut (result, "a", offset--);
8467     }
8468   _endLazyDPSEvaluation ();
8469
8470   /* now we need to put the carry into the
8471      highest order byte of the result */
8472   if (AOP_SIZE (result) > 1)
8473     {
8474       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8475       MOVA (l);
8476     }
8477   emitcode ("mov", "acc.7,c");
8478   aopPut (result, "a", AOP_SIZE (result) - 1);
8479   freeAsmop (result, NULL, ic, TRUE);
8480   freeAsmop (left, NULL, ic, TRUE);
8481 }
8482
8483 /*-----------------------------------------------------------------*/
8484 /* genRLC - generate code for rotate left with carry               */
8485 /*-----------------------------------------------------------------*/
8486 static void
8487 genRLC (iCode * ic)
8488 {
8489   operand *left, *result;
8490   int size, offset;
8491   char *l;
8492
8493   D (emitcode (";", "genRLC"));
8494
8495   /* rotate right with carry */
8496   left = IC_LEFT (ic);
8497   result = IC_RESULT (ic);
8498   aopOp (left, ic, FALSE, FALSE);
8499   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8500
8501   /* move it to the result */
8502   size = AOP_SIZE (result);
8503   offset = 0;
8504   if (size--)
8505     {
8506       l = aopGet (left, offset, FALSE, FALSE, NULL);
8507       MOVA (l);
8508       emitcode ("add", "a,acc");
8509       if (AOP_SIZE (result) > 1)
8510         {
8511           aopPut (result, "a", offset++);
8512         }
8513
8514       _startLazyDPSEvaluation ();
8515       while (size--)
8516         {
8517           l = aopGet (left, offset, FALSE, FALSE, NULL);
8518           MOVA (l);
8519           emitcode ("rlc", "a");
8520           if (AOP_SIZE (result) > 1)
8521             aopPut (result, "a", offset++);
8522         }
8523       _endLazyDPSEvaluation ();
8524     }
8525   /* now we need to put the carry into the
8526      highest order byte of the result */
8527   if (AOP_SIZE (result) > 1)
8528     {
8529       l = aopGet (result, 0, FALSE, FALSE, NULL);
8530       MOVA (l);
8531     }
8532   emitcode ("mov", "acc.0,c");
8533   aopPut (result, "a", 0);
8534   freeAsmop (result, NULL, ic, TRUE);
8535   freeAsmop (left, NULL, ic, TRUE);
8536 }
8537
8538 /*-----------------------------------------------------------------*/
8539 /* genGetHbit - generates code get highest order bit               */
8540 /*-----------------------------------------------------------------*/
8541 static void
8542 genGetHbit (iCode * ic)
8543 {
8544   operand *left, *result;
8545
8546   D (emitcode (";", "genGetHbit"));
8547
8548   left = IC_LEFT (ic);
8549   result = IC_RESULT (ic);
8550   aopOp (left, ic, FALSE, FALSE);
8551   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8552
8553   /* get the highest order byte into a */
8554   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8555   if (AOP_TYPE (result) == AOP_CRY)
8556     {
8557       emitcode ("rlc", "a");
8558       outBitC (result);
8559     }
8560   else
8561     {
8562       emitcode ("rl", "a");
8563       emitcode ("anl", "a,#0x01");
8564       outAcc (result);
8565     }
8566
8567
8568   freeAsmop (result, NULL, ic, TRUE);
8569   freeAsmop (left, NULL, ic, TRUE);
8570 }
8571
8572 /*-----------------------------------------------------------------*/
8573 /* genSwap - generates code to swap nibbles or bytes               */
8574 /*-----------------------------------------------------------------*/
8575 static void
8576 genSwap (iCode * ic)
8577 {
8578   operand *left, *result;
8579
8580   D(emitcode (";", "genSwap"));
8581
8582   left = IC_LEFT (ic);
8583   result = IC_RESULT (ic);
8584   aopOp (left, ic, FALSE, FALSE);
8585   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8586
8587   _startLazyDPSEvaluation ();
8588   switch (AOP_SIZE (left))
8589     {
8590     case 1: /* swap nibbles in byte */
8591       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8592       emitcode ("swap", "a");
8593       aopPut (result, "a", 0);
8594       break;
8595     case 2: /* swap bytes in word */
8596       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8597         {
8598           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8599           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8600           aopPut (result, "a", 1);
8601         }
8602       else if (operandsEqu (left, result))
8603         {
8604           char * reg = "a";
8605           bool pushedB = FALSE, leftInB = FALSE;
8606
8607           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8608           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8609             {
8610               pushedB = pushB ();
8611               emitcode ("mov", "b,a");
8612               reg = "b";
8613               leftInB = TRUE;
8614             }
8615           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8616           aopPut (result, reg, 1);
8617
8618           if (leftInB)
8619             popB (pushedB);
8620         }
8621       else
8622         {
8623           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8624           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8625         }
8626       break;
8627     default:
8628       wassertl(FALSE, "unsupported SWAP operand size");
8629     }
8630   _endLazyDPSEvaluation ();
8631
8632   freeAsmop (result, NULL, ic, TRUE);
8633   freeAsmop (left, NULL, ic, TRUE);
8634 }
8635
8636 /*-----------------------------------------------------------------*/
8637 /* AccRol - rotate left accumulator by known count                 */
8638 /*-----------------------------------------------------------------*/
8639 static void
8640 AccRol (int shCount)
8641 {
8642   shCount &= 0x0007;            // shCount : 0..7
8643
8644   switch (shCount)
8645     {
8646     case 0:
8647       break;
8648     case 1:
8649       emitcode ("rl", "a");
8650       break;
8651     case 2:
8652       emitcode ("rl", "a");
8653       emitcode ("rl", "a");
8654       break;
8655     case 3:
8656       emitcode ("swap", "a");
8657       emitcode ("rr", "a");
8658       break;
8659     case 4:
8660       emitcode ("swap", "a");
8661       break;
8662     case 5:
8663       emitcode ("swap", "a");
8664       emitcode ("rl", "a");
8665       break;
8666     case 6:
8667       emitcode ("rr", "a");
8668       emitcode ("rr", "a");
8669       break;
8670     case 7:
8671       emitcode ("rr", "a");
8672       break;
8673     }
8674 }
8675
8676 /*-----------------------------------------------------------------*/
8677 /* AccLsh - left shift accumulator by known count                  */
8678 /*-----------------------------------------------------------------*/
8679 static void
8680 AccLsh (int shCount)
8681 {
8682   if (shCount != 0)
8683     {
8684       if (shCount == 1)
8685         emitcode ("add", "a,acc");
8686       else if (shCount == 2)
8687         {
8688           emitcode ("add", "a,acc");
8689           emitcode ("add", "a,acc");
8690         }
8691       else
8692         {
8693           /* rotate left accumulator */
8694           AccRol (shCount);
8695           /* and kill the lower order bits */
8696           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8697         }
8698     }
8699 }
8700
8701 /*-----------------------------------------------------------------*/
8702 /* AccRsh - right shift accumulator by known count                 */
8703 /*-----------------------------------------------------------------*/
8704 static void
8705 AccRsh (int shCount)
8706 {
8707   if (shCount != 0)
8708     {
8709       if (shCount == 1)
8710         {
8711           CLRC;
8712           emitcode ("rrc", "a");
8713         }
8714       else
8715         {
8716           /* rotate right accumulator */
8717           AccRol (8 - shCount);
8718           /* and kill the higher order bits */
8719           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8720         }
8721     }
8722 }
8723
8724 #ifdef BETTER_LITERAL_SHIFT
8725 /*-----------------------------------------------------------------*/
8726 /* AccSRsh - signed right shift accumulator by known count                 */
8727 /*-----------------------------------------------------------------*/
8728 static void
8729 AccSRsh (int shCount)
8730 {
8731   symbol *tlbl;
8732   if (shCount != 0)
8733     {
8734       if (shCount == 1)
8735         {
8736           emitcode ("mov", "c,acc.7");
8737           emitcode ("rrc", "a");
8738         }
8739       else if (shCount == 2)
8740         {
8741           emitcode ("mov", "c,acc.7");
8742           emitcode ("rrc", "a");
8743           emitcode ("mov", "c,acc.7");
8744           emitcode ("rrc", "a");
8745         }
8746       else
8747         {
8748           tlbl = newiTempLabel (NULL);
8749           /* rotate right accumulator */
8750           AccRol (8 - shCount);
8751           /* and kill the higher order bits */
8752           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8753           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8754           emitcode ("orl", "a,#!constbyte",
8755                     (unsigned char) ~SRMask[shCount]);
8756           emitLabel (tlbl);
8757         }
8758     }
8759 }
8760 #endif
8761
8762 #ifdef BETTER_LITERAL_SHIFT
8763 /*-----------------------------------------------------------------*/
8764 /* shiftR1Left2Result - shift right one byte from left to result   */
8765 /*-----------------------------------------------------------------*/
8766 static void
8767 shiftR1Left2Result (operand * left, int offl,
8768                     operand * result, int offr,
8769                     int shCount, int sign)
8770 {
8771   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8772   /* shift right accumulator */
8773   if (sign)
8774     AccSRsh (shCount);
8775   else
8776     AccRsh (shCount);
8777   aopPut (result, "a", offr);
8778 }
8779 #endif
8780
8781 #ifdef BETTER_LITERAL_SHIFT
8782 /*-----------------------------------------------------------------*/
8783 /* shiftL1Left2Result - shift left one byte from left to result    */
8784 /*-----------------------------------------------------------------*/
8785 static void
8786 shiftL1Left2Result (operand * left, int offl,
8787                     operand * result, int offr, int shCount)
8788 {
8789   char *l;
8790   l = aopGet (left, offl, FALSE, FALSE, NULL);
8791   MOVA (l);
8792   /* shift left accumulator */
8793   AccLsh (shCount);
8794   aopPut (result, "a", offr);
8795 }
8796 #endif
8797
8798 #ifdef BETTER_LITERAL_SHIFT
8799 /*-----------------------------------------------------------------*/
8800 /* movLeft2Result - move byte from left to result                  */
8801 /*-----------------------------------------------------------------*/
8802 static void
8803 movLeft2Result (operand * left, int offl,
8804                 operand * result, int offr, int sign)
8805 {
8806   char *l;
8807   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8808   {
8809       l = aopGet (left, offl, FALSE, FALSE, NULL);
8810
8811       if (*l == '@' && (IS_AOP_PREG (result)))
8812         {
8813           emitcode ("mov", "a,%s", l);
8814           aopPut (result, "a", offr);
8815         }
8816       else
8817         {
8818           if (!sign)
8819             {
8820               aopPut (result, l, offr);
8821             }
8822           else
8823             {
8824               /* MSB sign in acc.7 ! */
8825               if (getDataSize (left) == offl + 1)
8826                 {
8827                   MOVA (l);
8828                   aopPut (result, "a", offr);
8829                 }
8830             }
8831         }
8832     }
8833 }
8834 #endif
8835
8836 #ifdef BETTER_LITERAL_SHIFT
8837 /*-----------------------------------------------------------------*/
8838 /* AccAXRrl1 - right rotate a:x by 1                               */
8839 /*-----------------------------------------------------------------*/
8840 static void
8841 AccAXRrl1 (char *x)
8842 {
8843   emitcode ("mov", "c,acc.0");
8844   emitcode ("xch", "a,%s", x);
8845   emitcode ("rrc", "a");
8846   emitcode ("xch", "a,%s", x);
8847   emitcode ("rrc", "a");
8848 }
8849 #endif
8850
8851 #ifdef BETTER_LITERAL_SHIFT
8852 //REMOVE ME!!!
8853 /*-----------------------------------------------------------------*/
8854 /* AccAXLrl1 - left rotate a:x by 1                                */
8855 /*-----------------------------------------------------------------*/
8856 static void
8857 AccAXLrl1 (char *x)
8858 {
8859   emitcode ("mov", "c,acc.7");
8860   emitcode ("xch", "a,%s", x);
8861   emitcode ("rlc", "a");
8862   emitcode ("xch", "a,%s", x);
8863   emitcode ("rlc", "a");
8864 }
8865 #endif
8866
8867 #ifdef BETTER_LITERAL_SHIFT
8868 /*-----------------------------------------------------------------*/
8869 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8870 /*-----------------------------------------------------------------*/
8871 static void
8872 AccAXRsh1 (char *x)
8873 {
8874   emitcode ("rrc", "a");
8875   emitcode ("xch", "a,%s", x);
8876   emitcode ("rrc", "a");
8877   emitcode ("xch", "a,%s", x);
8878 }
8879 #endif
8880
8881 #ifdef BETTER_LITERAL_SHIFT
8882 /*-----------------------------------------------------------------*/
8883 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8884 /*-----------------------------------------------------------------*/
8885 static void
8886 AccAXLsh1 (char *x)
8887 {
8888   emitcode ("xch", "a,%s", x);
8889   emitcode ("add", "a,acc");
8890   emitcode ("xch", "a,%s", x);
8891   emitcode ("rlc", "a");
8892 }
8893 #endif
8894
8895 #ifdef BETTER_LITERAL_SHIFT
8896 /*-----------------------------------------------------------------*/
8897 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8898 /*-----------------------------------------------------------------*/
8899 static void
8900 AccAXLsh (char *x, int shCount)
8901 {
8902   switch (shCount)
8903     {
8904     case 0:
8905       break;
8906     case 1:
8907       AccAXLsh1 (x);
8908       break;
8909     case 2:
8910       AccAXLsh1 (x);
8911       AccAXLsh1 (x);
8912       break;
8913     case 3:
8914     case 4:
8915     case 5:                             // AAAAABBB:CCCCCDDD
8916
8917       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8918
8919       emitcode ("anl", "a,#!constbyte",
8920                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8921
8922       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8923
8924       AccRol (shCount);                 // DDDCCCCC:BBB00000
8925
8926       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8927
8928       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8929
8930       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8931
8932       emitcode ("anl", "a,#!constbyte",
8933                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8934
8935       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8936
8937       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8938
8939       break;
8940     case 6:                             // AAAAAABB:CCCCCCDD
8941       emitcode ("anl", "a,#!constbyte",
8942                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8943 #if 1
8944       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8945       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8946       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8947 #else
8948       emitcode ("mov", "c,acc.0");      // c = B
8949       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8950       emitcode("rrc","a");
8951       emitcode("xch","a,%s", x);
8952       emitcode("rrc","a");
8953       emitcode("mov","c,acc.0"); //<< get correct bit
8954       emitcode("xch","a,%s", x);
8955
8956       emitcode("rrc","a");
8957       emitcode("xch","a,%s", x);
8958       emitcode("rrc","a");
8959       emitcode("xch","a,%s", x);
8960 #endif
8961       break;
8962     case 7:                             // a:x <<= 7
8963
8964       emitcode ("anl", "a,#!constbyte",
8965                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8966
8967       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8968
8969       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8970
8971       break;
8972     default:
8973       break;
8974     }
8975 }
8976 #endif
8977
8978 #ifdef BETTER_LITERAL_SHIFT
8979 //REMOVE ME!!!
8980 /*-----------------------------------------------------------------*/
8981 /* AccAXRsh - right shift a:x known count (0..7)                   */
8982 /*-----------------------------------------------------------------*/
8983 static void
8984 AccAXRsh (char *x, int shCount)
8985 {
8986   switch (shCount)
8987     {
8988     case 0:
8989       break;
8990     case 1:
8991       CLRC;
8992       AccAXRsh1 (x);                    // 0->a:x
8993
8994       break;
8995     case 2:
8996       CLRC;
8997       AccAXRsh1 (x);                    // 0->a:x
8998
8999       CLRC;
9000       AccAXRsh1 (x);                    // 0->a:x
9001
9002       break;
9003     case 3:
9004     case 4:
9005     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9006
9007       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
9008
9009       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9010
9011       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9012
9013       emitcode ("anl", "a,#!constbyte",
9014                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9015
9016       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9017
9018       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9019
9020       emitcode ("anl", "a,#!constbyte",
9021                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9022
9023       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9024
9025       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9026
9027       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
9028
9029       break;
9030     case 6:                             // AABBBBBB:CCDDDDDD
9031
9032       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
9033       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9034
9035       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9036
9037       emitcode ("anl", "a,#!constbyte",
9038                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9039
9040       break;
9041     case 7:                             // ABBBBBBB:CDDDDDDD
9042
9043       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9044
9045       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9046
9047       emitcode ("anl", "a,#!constbyte",
9048                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9049
9050       break;
9051     default:
9052       break;
9053     }
9054 }
9055 #endif
9056
9057 #ifdef BETTER_LITERAL_SHIFT
9058 /*-----------------------------------------------------------------*/
9059 /* AccAXRshS - right shift signed a:x known count (0..7)           */
9060 /*-----------------------------------------------------------------*/
9061 static void
9062 AccAXRshS (char *x, int shCount)
9063 {
9064   symbol *tlbl;
9065   switch (shCount)
9066     {
9067     case 0:
9068       break;
9069     case 1:
9070       emitcode ("mov", "c,acc.7");
9071       AccAXRsh1 (x);                    // s->a:x
9072
9073       break;
9074     case 2:
9075       emitcode ("mov", "c,acc.7");
9076       AccAXRsh1 (x);                    // s->a:x
9077
9078       emitcode ("mov", "c,acc.7");
9079       AccAXRsh1 (x);                    // s->a:x
9080
9081       break;
9082     case 3:
9083     case 4:
9084     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9085
9086       tlbl = newiTempLabel (NULL);
9087       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9088
9089       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9090
9091       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9092
9093       emitcode ("anl", "a,#!constbyte",
9094                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9095
9096       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9097
9098       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9099
9100       emitcode ("anl", "a,#!constbyte",
9101                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9102
9103       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9104
9105       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9106
9107       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9108
9109       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9110       emitcode ("orl", "a,#!constbyte",
9111                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9112
9113       emitLabel (tlbl);
9114       break;                            // SSSSAAAA:BBBCCCCC
9115
9116     case 6:                             // AABBBBBB:CCDDDDDD
9117
9118       tlbl = newiTempLabel (NULL);
9119
9120       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9121       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9122
9123       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9124
9125       emitcode ("anl", "a,#!constbyte",
9126                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9127
9128       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9129       emitcode ("orl", "a,#!constbyte",
9130                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9131
9132       emitLabel (tlbl);
9133       break;
9134     case 7:                             // ABBBBBBB:CDDDDDDD
9135
9136       tlbl = newiTempLabel (NULL);
9137
9138       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9139
9140       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9141
9142       emitcode ("anl", "a,#!constbyte",
9143                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9144
9145       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9146       emitcode ("orl", "a,#!constbyte",
9147                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9148
9149       emitLabel (tlbl);
9150       break;
9151     default:
9152       break;
9153     }
9154 }
9155 #endif
9156
9157 #ifdef BETTER_LITERAL_SHIFT
9158 static void
9159 _loadLeftIntoAx(char    **lsb,
9160                 operand *left,
9161                 operand *result,
9162                 int     offl,
9163                 int     offr)
9164 {
9165   // Get the initial value from left into a pair of registers.
9166   // MSB must be in A, LSB can be any register.
9167   //
9168   // If the result is held in registers, it is an optimization
9169   // if the LSB can be held in the register which will hold the,
9170   // result LSB since this saves us from having to copy it into
9171   // the result following AccAXLsh.
9172   //
9173   // If the result is addressed indirectly, this is not a gain.
9174   if (AOP_NEEDSACC(result))
9175   {
9176        char *leftByte;
9177
9178        _startLazyDPSEvaluation();
9179       if (AOP_TYPE(left) == AOP_DPTR2)
9180        {
9181            // Get MSB in A.
9182            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9183            // get LSB in DP2_RESULT_REG.
9184            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9185            assert(!strcmp(leftByte, DP2_RESULT_REG));
9186        }
9187        else
9188        {
9189            // get LSB into DP2_RESULT_REG
9190            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9191            if (strcmp(leftByte, DP2_RESULT_REG))
9192            {
9193                TR_AP("#7");
9194                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9195            }
9196            // And MSB in A.
9197            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9198            assert(strcmp(leftByte, DP2_RESULT_REG));
9199            MOVA (leftByte);
9200        }
9201        _endLazyDPSEvaluation();
9202        *lsb = DP2_RESULT_REG;
9203   }
9204   else
9205   {
9206       if (sameRegs (AOP (result), AOP (left)) &&
9207         ((offl + MSB16) == offr))
9208       {
9209           /* don't crash result[offr] */
9210           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9211           emitcode ("xch", "a,%s",
9212                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9213       }
9214       else
9215       {
9216           movLeft2Result (left, offl, result, offr, 0);
9217           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9218       }
9219       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9220       assert(strcmp(*lsb,"a"));
9221   }
9222 }
9223
9224 static void
9225 _storeAxResults(char    *lsb,
9226                 operand *result,
9227                 int     offr)
9228 {
9229   _startLazyDPSEvaluation();
9230   if (AOP_NEEDSACC(result))
9231   {
9232       /* We have to explicitly update the result LSB.
9233        */
9234       emitcode ("xch","a,%s", lsb);
9235       aopPut (result, "a", offr);
9236       emitcode ("mov","a,%s", lsb);
9237   }
9238   if (getDataSize (result) > 1)
9239   {
9240       aopPut (result, "a", offr + MSB16);
9241   }
9242   _endLazyDPSEvaluation();
9243 }
9244
9245 /*-----------------------------------------------------------------*/
9246 /* shiftL2Left2Result - shift left two bytes from left to result   */
9247 /*-----------------------------------------------------------------*/
9248 static void
9249 shiftL2Left2Result (operand * left, int offl,
9250                     operand * result, int offr, int shCount)
9251 {
9252   char *lsb;
9253
9254   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9255
9256   AccAXLsh (lsb, shCount);
9257
9258   _storeAxResults(lsb, result, offr);
9259 }
9260 #endif
9261
9262 #ifdef BETTER_LITERAL_SHIFT
9263 /*-----------------------------------------------------------------*/
9264 /* shiftR2Left2Result - shift right two bytes from left to result  */
9265 /*-----------------------------------------------------------------*/
9266 static void
9267 shiftR2Left2Result (operand * left, int offl,
9268                     operand * result, int offr,
9269                     int shCount, int sign)
9270 {
9271   char *lsb;
9272
9273   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9274
9275   /* a:x >> shCount (x = lsb(result)) */
9276   if (sign)
9277   {
9278      AccAXRshS(lsb, shCount);
9279   }
9280   else
9281   {
9282     AccAXRsh(lsb, shCount);
9283   }
9284
9285   _storeAxResults(lsb, result, offr);
9286 }
9287 #endif
9288
9289 /*-----------------------------------------------------------------*/
9290 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9291 /*-----------------------------------------------------------------*/
9292 static void
9293 shiftLLeftOrResult (operand * left, int offl,
9294                     operand * result, int offr, int shCount)
9295 {
9296   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9297   /* shift left accumulator */
9298   AccLsh (shCount);
9299   /* or with result */
9300   emitcode ("orl", "a,%s",
9301             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9302   /* back to result */
9303   aopPut (result, "a", offr);
9304 }
9305
9306 #if 0
9307 //REMOVE ME!!!
9308 /*-----------------------------------------------------------------*/
9309 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9310 /*-----------------------------------------------------------------*/
9311 static void
9312 shiftRLeftOrResult (operand * left, int offl,
9313                     operand * result, int offr, int shCount)
9314 {
9315   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9316   /* shift right accumulator */
9317   AccRsh (shCount);
9318   /* or with result */
9319   emitcode ("orl", "a,%s",
9320             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9321   /* back to result */
9322   aopPut (result, "a", offr);
9323 }
9324 #endif
9325
9326 #ifdef BETTER_LITERAL_SHIFT
9327 /*-----------------------------------------------------------------*/
9328 /* genlshOne - left shift a one byte quantity by known count       */
9329 /*-----------------------------------------------------------------*/
9330 static void
9331 genlshOne (operand * result, operand * left, int shCount)
9332 {
9333   D (emitcode (";", "genlshOne"));
9334
9335   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9336 }
9337 #endif
9338
9339 #ifdef BETTER_LITERAL_SHIFT
9340 /*-----------------------------------------------------------------*/
9341 /* genlshTwo - left shift two bytes by known amount != 0           */
9342 /*-----------------------------------------------------------------*/
9343 static void
9344 genlshTwo (operand * result, operand * left, int shCount)
9345 {
9346   int size;
9347
9348   D (emitcode (";", "genlshTwo"));
9349
9350   size = getDataSize (result);
9351
9352   /* if shCount >= 8 */
9353   if (shCount >= 8)
9354     {
9355       shCount -= 8;
9356
9357       _startLazyDPSEvaluation();
9358
9359       if (size > 1)
9360         {
9361           if (shCount)
9362             {
9363               _endLazyDPSEvaluation();
9364               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9365               aopPut (result, zero, LSB);
9366             }
9367           else
9368             {
9369               movLeft2Result (left, LSB, result, MSB16, 0);
9370               aopPut (result, zero, LSB);
9371               _endLazyDPSEvaluation();
9372             }
9373         }
9374       else
9375         {
9376           aopPut (result, zero, LSB);
9377           _endLazyDPSEvaluation();
9378         }
9379   }
9380
9381   /*  1 <= shCount <= 7 */
9382   else
9383     {
9384       if (size == 1)
9385         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9386       else
9387         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9388     }
9389 }
9390 #endif
9391
9392 #if 0
9393 //REMOVE ME!!!
9394 /*-----------------------------------------------------------------*/
9395 /* shiftLLong - shift left one long from left to result            */
9396 /* offl = LSB or MSB16                                             */
9397 /*-----------------------------------------------------------------*/
9398 static void
9399 shiftLLong (operand * left, operand * result, int offr)
9400 {
9401   char *l;
9402   int size = AOP_SIZE (result);
9403
9404   if (size >= LSB + offr)
9405     {
9406       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9407       MOVA (l);
9408       emitcode ("add", "a,acc");
9409       if (sameRegs (AOP (left), AOP (result)) &&
9410           size >= MSB16 + offr && offr != LSB)
9411         emitcode ("xch", "a,%s",
9412                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9413       else
9414         aopPut (result, "a", LSB + offr);
9415     }
9416
9417   if (size >= MSB16 + offr)
9418     {
9419       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9420         {
9421           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9422           MOVA (l);
9423         }
9424       emitcode ("rlc", "a");
9425       if (sameRegs (AOP (left), AOP (result)) &&
9426           size >= MSB24 + offr && offr != LSB)
9427         emitcode ("xch", "a,%s",
9428                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9429       else
9430         aopPut (result, "a", MSB16 + offr);
9431     }
9432
9433   if (size >= MSB24 + offr)
9434     {
9435       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9436         {
9437           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9438           MOVA (l);
9439         }
9440       emitcode ("rlc", "a");
9441       if (sameRegs (AOP (left), AOP (result)) &&
9442           size >= MSB32 + offr && offr != LSB)
9443         emitcode ("xch", "a,%s",
9444                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9445       else
9446         aopPut (result, "a", MSB24 + offr);
9447     }
9448
9449   if (size > MSB32 + offr)
9450     {
9451       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9452         {
9453           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9454           MOVA (l);
9455         }
9456       emitcode ("rlc", "a");
9457       aopPut (result, "a", MSB32 + offr);
9458     }
9459   if (offr != LSB)
9460     aopPut (result, zero, LSB);
9461 }
9462 #endif
9463
9464 #if 0
9465 //REMOVE ME!!!
9466 /*-----------------------------------------------------------------*/
9467 /* genlshFour - shift four byte by a known amount != 0             */
9468 /*-----------------------------------------------------------------*/
9469 static void
9470 genlshFour (operand * result, operand * left, int shCount)
9471 {
9472   int size;
9473
9474   D (emitcode (";", "genlshFour"));
9475
9476   size = AOP_SIZE (result);
9477
9478   /* if shifting more that 3 bytes */
9479   if (shCount >= 24)
9480     {
9481       shCount -= 24;
9482       if (shCount)
9483         /* lowest order of left goes to the highest
9484            order of the destination */
9485         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9486       else
9487         movLeft2Result (left, LSB, result, MSB32, 0);
9488       aopPut (result, zero, LSB);
9489       aopPut (result, zero, MSB16);
9490       aopPut (result, zero, MSB24);
9491       return;
9492     }
9493
9494   /* more than two bytes */
9495   else if (shCount >= 16)
9496     {
9497       /* lower order two bytes goes to higher order two bytes */
9498       shCount -= 16;
9499       /* if some more remaining */
9500       if (shCount)
9501         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9502       else
9503         {
9504           movLeft2Result (left, MSB16, result, MSB32, 0);
9505           movLeft2Result (left, LSB, result, MSB24, 0);
9506         }
9507       aopPut (result, zero, MSB16);
9508       aopPut (result, zero, LSB);
9509       return;
9510     }
9511
9512   /* if more than 1 byte */
9513   else if (shCount >= 8)
9514     {
9515       /* lower order three bytes goes to higher order  three bytes */
9516       shCount -= 8;
9517       if (size == 2)
9518         {
9519           if (shCount)
9520             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9521           else
9522             movLeft2Result (left, LSB, result, MSB16, 0);
9523         }
9524       else
9525         {                       /* size = 4 */
9526           if (shCount == 0)
9527             {
9528               movLeft2Result (left, MSB24, result, MSB32, 0);
9529               movLeft2Result (left, MSB16, result, MSB24, 0);
9530               movLeft2Result (left, LSB, result, MSB16, 0);
9531               aopPut (result, zero, LSB);
9532             }
9533           else if (shCount == 1)
9534             shiftLLong (left, result, MSB16);
9535           else
9536             {
9537               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9538               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9539               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9540               aopPut (result, zero, LSB);
9541             }
9542         }
9543     }
9544
9545   /* 1 <= shCount <= 7 */
9546   else if (shCount <= 2)
9547     {
9548       shiftLLong (left, result, LSB);
9549       if (shCount == 2)
9550         shiftLLong (result, result, LSB);
9551     }
9552   /* 3 <= shCount <= 7, optimize */
9553   else
9554     {
9555       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9556       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9557       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9558     }
9559 }
9560 #endif
9561
9562 #ifdef BETTER_LITERAL_SHIFT
9563 /*-----------------------------------------------------------------*/
9564 /* genLeftShiftLiteral - left shifting by known count              */
9565 /*-----------------------------------------------------------------*/
9566 static bool
9567 genLeftShiftLiteral (operand * left,
9568                      operand * right,
9569                      operand * result,
9570                      iCode * ic)
9571 {
9572   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9573   int size;
9574
9575   size = getSize (operandType (result));
9576
9577   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9578
9579   /* We only handle certain easy cases so far. */
9580   if ((shCount != 0)
9581    && (shCount < (size * 8))
9582    && (size != 1)
9583    && (size != 2))
9584   {
9585       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9586       return FALSE;
9587   }
9588
9589   freeAsmop (right, NULL, ic, TRUE);
9590
9591   aopOp(left, ic, FALSE, FALSE);
9592   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9593
9594 #if 0 // debug spew
9595   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9596   {
9597         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9598         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9599         {
9600            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9601         }
9602   }
9603   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9604   {
9605         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9606         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9607         {
9608            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9609         }
9610   }
9611 #endif
9612
9613 #if VIEW_SIZE
9614   emitcode ("; shift left ", "result %d, left %d", size,
9615             AOP_SIZE (left));
9616 #endif
9617
9618   /* I suppose that the left size >= result size */
9619   if (shCount == 0)
9620     {
9621       _startLazyDPSEvaluation();
9622       while (size--)
9623         {
9624           movLeft2Result (left, size, result, size, 0);
9625         }
9626       _endLazyDPSEvaluation();
9627     }
9628   else if (shCount >= (size * 8))
9629     {
9630       _startLazyDPSEvaluation();
9631       while (size--)
9632         {
9633           aopPut (result, zero, size);
9634         }
9635       _endLazyDPSEvaluation();
9636     }
9637   else
9638     {
9639       switch (size)
9640         {
9641         case 1:
9642           genlshOne (result, left, shCount);
9643           break;
9644
9645         case 2:
9646           genlshTwo (result, left, shCount);
9647           break;
9648 #if 0
9649         case 4:
9650           genlshFour (result, left, shCount);
9651           break;
9652 #endif
9653         default:
9654           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9655                   "*** ack! mystery literal shift!\n");
9656           break;
9657         }
9658     }
9659   freeAsmop (result, NULL, ic, TRUE);
9660   freeAsmop (left, NULL, ic, TRUE);
9661   return TRUE;
9662 }
9663 #endif
9664
9665 /*-----------------------------------------------------------------*/
9666 /* genLeftShift - generates code for left shifting                 */
9667 /*-----------------------------------------------------------------*/
9668 static void
9669 genLeftShift (iCode * ic)
9670 {
9671   operand *left, *right, *result;
9672   int size, offset;
9673   char *l;
9674   symbol *tlbl, *tlbl1;
9675   bool pushedB;
9676
9677   D (emitcode (";", "genLeftShift"));
9678
9679   right = IC_RIGHT (ic);
9680   left = IC_LEFT (ic);
9681   result = IC_RESULT (ic);
9682
9683   aopOp (right, ic, FALSE, FALSE);
9684
9685
9686 #ifdef BETTER_LITERAL_SHIFT
9687   /* if the shift count is known then do it
9688      as efficiently as possible */
9689   if (AOP_TYPE (right) == AOP_LIT)
9690     {
9691       if (genLeftShiftLiteral (left, right, result, ic))
9692       {
9693         return;
9694       }
9695     }
9696 #endif
9697
9698   /* shift count is unknown then we have to form
9699      a loop get the loop count in B : Note: we take
9700      only the lower order byte since shifting
9701      more that 32 bits make no sense anyway, ( the
9702      largest size of an object can be only 32 bits ) */
9703
9704   pushedB = pushB ();
9705   if (AOP_TYPE (right) == AOP_LIT)
9706   {
9707       /* Really should be handled by genLeftShiftLiteral,
9708        * but since I'm too lazy to fix that today, at least we can make
9709        * some small improvement.
9710        */
9711        emitcode("mov", "b,#!constbyte",
9712                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
9713   }
9714   else
9715   {
9716       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9717       emitcode ("inc", "b");
9718   }
9719   freeAsmop (right, NULL, ic, TRUE);
9720   aopOp (left, ic, FALSE, FALSE);
9721   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9722
9723   /* now move the left to the result if they are not the same */
9724   if (!sameRegs (AOP (left), AOP (result)) &&
9725       AOP_SIZE (result) > 1)
9726     {
9727
9728       size = AOP_SIZE (result);
9729       offset = 0;
9730       _startLazyDPSEvaluation ();
9731       while (size--)
9732         {
9733           l = aopGet (left, offset, FALSE, TRUE, NULL);
9734           if (*l == '@' && (IS_AOP_PREG (result)))
9735             {
9736
9737               emitcode ("mov", "a,%s", l);
9738               aopPut (result, "a", offset);
9739             }
9740           else
9741             aopPut (result, l, offset);
9742           offset++;
9743         }
9744       _endLazyDPSEvaluation ();
9745     }
9746
9747   tlbl = newiTempLabel (NULL);
9748   size = AOP_SIZE (result);
9749   offset = 0;
9750   tlbl1 = newiTempLabel (NULL);
9751
9752   /* if it is only one byte then */
9753   if (size == 1)
9754     {
9755       symbol *tlbl1 = newiTempLabel (NULL);
9756
9757       l = aopGet (left, 0, FALSE, FALSE, NULL);
9758       MOVA (l);
9759       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9760       emitLabel (tlbl);
9761       emitcode ("add", "a,acc");
9762       emitLabel (tlbl1);
9763       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9764       popB (pushedB);
9765       aopPut (result, "a", 0);
9766       goto release;
9767     }
9768
9769   reAdjustPreg (AOP (result));
9770
9771   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9772   emitLabel (tlbl);
9773   l = aopGet (result, offset, FALSE, FALSE, NULL);
9774   MOVA (l);
9775   emitcode ("add", "a,acc");
9776   aopPut (result, "a", offset++);
9777   _startLazyDPSEvaluation ();
9778   while (--size)
9779     {
9780       l = aopGet (result, offset, FALSE, FALSE, NULL);
9781       MOVA (l);
9782       emitcode ("rlc", "a");
9783       aopPut (result, "a", offset++);
9784     }
9785   _endLazyDPSEvaluation ();
9786   reAdjustPreg (AOP (result));
9787
9788   emitLabel (tlbl1);
9789   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9790   popB (pushedB);
9791 release:
9792   freeAsmop (result, NULL, ic, TRUE);
9793   freeAsmop (left, NULL, ic, TRUE);
9794 }
9795
9796 #ifdef BETTER_LITERAL_SHIFT
9797 /*-----------------------------------------------------------------*/
9798 /* genrshOne - right shift a one byte quantity by known count      */
9799 /*-----------------------------------------------------------------*/
9800 static void
9801 genrshOne (operand * result, operand * left,
9802            int shCount, int sign)
9803 {
9804   D (emitcode (";", "genrshOne"));
9805
9806   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9807 }
9808 #endif
9809
9810 #ifdef BETTER_LITERAL_SHIFT
9811 /*-----------------------------------------------------------------*/
9812 /* genrshTwo - right shift two bytes by known amount != 0          */
9813 /*-----------------------------------------------------------------*/
9814 static void
9815 genrshTwo (operand * result, operand * left,
9816            int shCount, int sign)
9817 {
9818   D (emitcode (";", "genrshTwo"));
9819
9820   /* if shCount >= 8 */
9821   if (shCount >= 8)
9822     {
9823       shCount -= 8;
9824       _startLazyDPSEvaluation();
9825       if (shCount)
9826         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9827       else
9828         movLeft2Result (left, MSB16, result, LSB, sign);
9829       addSign (result, MSB16, sign);
9830       _endLazyDPSEvaluation();
9831     }
9832
9833   /*  1 <= shCount <= 7 */
9834   else
9835     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9836 }
9837 #endif
9838
9839 /*-----------------------------------------------------------------*/
9840 /* shiftRLong - shift right one long from left to result           */
9841 /* offl = LSB or MSB16                                             */
9842 /*-----------------------------------------------------------------*/
9843 static void
9844 shiftRLong (operand * left, int offl,
9845             operand * result, int sign)
9846 {
9847   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9848
9849   if (overlapping && offl>1)
9850     {
9851       // we are in big trouble, but this shouldn't happen
9852       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9853     }
9854
9855   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9856
9857   if (offl==MSB16)
9858     {
9859       // shift is > 8
9860       if (sign)
9861         {
9862           emitcode ("rlc", "a");
9863           emitcode ("subb", "a,acc");
9864           emitcode ("xch", "a,%s",
9865                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9866         }
9867       else
9868         {
9869           aopPut (result, zero, MSB32);
9870         }
9871     }
9872
9873   if (!sign)
9874     {
9875       emitcode ("clr", "c");
9876     }
9877   else
9878     {
9879       emitcode ("mov", "c,acc.7");
9880     }
9881
9882   emitcode ("rrc", "a");
9883
9884   if (overlapping && offl==MSB16)
9885     {
9886       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9887     }
9888   else
9889     {
9890       aopPut (result, "a", MSB32 - offl);
9891       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9892     }
9893
9894   emitcode ("rrc", "a");
9895
9896   if (overlapping && offl==MSB16)
9897     {
9898       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9899     }
9900   else
9901     {
9902       aopPut (result, "a", MSB24 - offl);
9903       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9904     }
9905
9906   emitcode ("rrc", "a");
9907   if (offl != LSB)
9908     {
9909       aopPut (result, "a", MSB16 - offl);
9910     }
9911   else
9912     {
9913       if (overlapping && offl==MSB16)
9914         {
9915           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9916         }
9917       else
9918         {
9919           aopPut (result, "a", MSB16 - offl);
9920           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9921         }
9922       emitcode ("rrc", "a");
9923       aopPut (result, "a", LSB);
9924     }
9925 }
9926
9927 /*-----------------------------------------------------------------*/
9928 /* genrshFour - shift four byte by a known amount != 0             */
9929 /*-----------------------------------------------------------------*/
9930 static void
9931 genrshFour (operand * result, operand * left,
9932             int shCount, int sign)
9933 {
9934   D (emitcode (";", "genrshFour"));
9935
9936   /* if shifting more that 3 bytes */
9937   if (shCount >= 24)
9938     {
9939       shCount -= 24;
9940       _startLazyDPSEvaluation();
9941       if (shCount)
9942         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9943       else
9944         movLeft2Result (left, MSB32, result, LSB, sign);
9945       addSign (result, MSB16, sign);
9946       _endLazyDPSEvaluation();
9947     }
9948   else if (shCount >= 16)
9949     {
9950       shCount -= 16;
9951       _startLazyDPSEvaluation();
9952       if (shCount)
9953         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9954       else
9955         {
9956           movLeft2Result (left, MSB24, result, LSB, 0);
9957           movLeft2Result (left, MSB32, result, MSB16, sign);
9958         }
9959       addSign (result, MSB24, sign);
9960       _endLazyDPSEvaluation();
9961     }
9962   else if (shCount >= 8)
9963     {
9964       shCount -= 8;
9965       _startLazyDPSEvaluation();
9966       if (shCount == 1)
9967         {
9968           shiftRLong (left, MSB16, result, sign);
9969         }
9970       else if (shCount == 0)
9971         {
9972           movLeft2Result (left, MSB16, result, LSB, 0);
9973           movLeft2Result (left, MSB24, result, MSB16, 0);
9974           movLeft2Result (left, MSB32, result, MSB24, sign);
9975           addSign (result, MSB32, sign);
9976         }
9977       else
9978         {
9979           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9980           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9981           /* the last shift is signed */
9982           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9983           addSign (result, MSB32, sign);
9984         }
9985         _endLazyDPSEvaluation();
9986     }
9987   else
9988     {
9989       /* 1 <= shCount <= 7 */
9990       if (shCount <= 2)
9991         {
9992           shiftRLong (left, LSB, result, sign);
9993           if (shCount == 2)
9994             shiftRLong (result, LSB, result, sign);
9995         }
9996       else
9997         {
9998           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9999           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
10000           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
10001         }
10002     }
10003 }
10004
10005 #ifdef BETTER_LITERAL_SHIFT
10006 /*-----------------------------------------------------------------*/
10007 /* genRightShiftLiteral - right shifting by known count            */
10008 /*-----------------------------------------------------------------*/
10009 static bool
10010 genRightShiftLiteral (operand * left,
10011                       operand * right,
10012                       operand * result,
10013                       iCode * ic,
10014                       int sign)
10015 {
10016   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10017   int size;
10018
10019   size = getSize (operandType (result));
10020
10021   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
10022
10023   /* We only handle certain easy cases so far. */
10024   if ((shCount != 0)
10025    && (shCount < (size * 8))
10026    && (size != 1)
10027    && (size != 2)
10028    && (size != 4))
10029   {
10030       D(emitcode (";", "genRightShiftLiteral wimping out"););
10031       return FALSE;
10032   }
10033
10034   freeAsmop (right, NULL, ic, TRUE);
10035
10036   aopOp (left, ic, FALSE, FALSE);
10037   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10038
10039 #if VIEW_SIZE
10040   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
10041             AOP_SIZE (left));
10042 #endif
10043
10044   /* test the LEFT size !!! */
10045
10046   /* I suppose that the left size >= result size */
10047   if (shCount == 0)
10048     {
10049       size = getDataSize (result);
10050       _startLazyDPSEvaluation();
10051       while (size--)
10052         movLeft2Result (left, size, result, size, 0);
10053       _endLazyDPSEvaluation();
10054     }
10055   else if (shCount >= (size * 8))
10056     {
10057       if (sign)
10058         {
10059           /* get sign in acc.7 */
10060           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
10061         }
10062       addSign (result, LSB, sign);
10063     }
10064   else
10065     {
10066       switch (size)
10067         {
10068         case 1:
10069           genrshOne (result, left, shCount, sign);
10070           break;
10071
10072         case 2:
10073           genrshTwo (result, left, shCount, sign);
10074           break;
10075 #if 1
10076         case 4:
10077           genrshFour (result, left, shCount, sign);
10078           break;
10079 #endif
10080         default:
10081           break;
10082         }
10083     }
10084   freeAsmop (result, NULL, ic, TRUE);
10085   freeAsmop (left, NULL, ic, TRUE);
10086
10087   return TRUE;
10088 }
10089 #endif
10090
10091 /*-----------------------------------------------------------------*/
10092 /* genSignedRightShift - right shift of signed number              */
10093 /*-----------------------------------------------------------------*/
10094 static void
10095 genSignedRightShift (iCode * ic)
10096 {
10097   operand *right, *left, *result;
10098   int size, offset;
10099   char *l;
10100   symbol *tlbl, *tlbl1;
10101   bool pushedB;
10102
10103   D (emitcode (";", "genSignedRightShift"));
10104
10105   /* we do it the hard way put the shift count in b
10106      and loop thru preserving the sign */
10107
10108   right = IC_RIGHT (ic);
10109   left = IC_LEFT (ic);
10110   result = IC_RESULT (ic);
10111
10112   aopOp (right, ic, FALSE, FALSE);
10113
10114 #ifdef BETTER_LITERAL_SHIFT
10115   if (AOP_TYPE (right) == AOP_LIT)
10116     {
10117       if (genRightShiftLiteral (left, right, result, ic, 1))
10118       {
10119         return;
10120       }
10121     }
10122 #endif
10123   /* shift count is unknown then we have to form
10124      a loop get the loop count in B : Note: we take
10125      only the lower order byte since shifting
10126      more that 32 bits make no sense anyway, ( the
10127      largest size of an object can be only 32 bits ) */
10128
10129   pushedB = pushB ();
10130   if (AOP_TYPE (right) == AOP_LIT)
10131   {
10132       /* Really should be handled by genRightShiftLiteral,
10133        * but since I'm too lazy to fix that today, at least we can make
10134        * some small improvement.
10135        */
10136        emitcode("mov", "b,#!constbyte",
10137                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10138   }
10139   else
10140   {
10141         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10142         emitcode ("inc", "b");
10143   }
10144   freeAsmop (right, NULL, ic, TRUE);
10145   aopOp (left, ic, FALSE, FALSE);
10146   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10147
10148   /* now move the left to the result if they are not the
10149      same */
10150   if (!sameRegs (AOP (left), AOP (result)) &&
10151       AOP_SIZE (result) > 1)
10152     {
10153
10154       size = AOP_SIZE (result);
10155       offset = 0;
10156       _startLazyDPSEvaluation ();
10157       while (size--)
10158         {
10159           l = aopGet (left, offset, FALSE, TRUE, NULL);
10160           if (*l == '@' && IS_AOP_PREG (result))
10161             {
10162
10163               emitcode ("mov", "a,%s", l);
10164               aopPut (result, "a", offset);
10165             }
10166           else
10167             aopPut (result, l, offset);
10168           offset++;
10169         }
10170       _endLazyDPSEvaluation ();
10171     }
10172
10173   /* mov the highest order bit to OVR */
10174   tlbl = newiTempLabel (NULL);
10175   tlbl1 = newiTempLabel (NULL);
10176
10177   size = AOP_SIZE (result);
10178   offset = size - 1;
10179   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10180   emitcode ("rlc", "a");
10181   emitcode ("mov", "ov,c");
10182   /* if it is only one byte then */
10183   if (size == 1)
10184     {
10185       l = aopGet (left, 0, FALSE, FALSE, NULL);
10186       MOVA (l);
10187       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10188       emitLabel (tlbl);
10189       emitcode ("mov", "c,ov");
10190       emitcode ("rrc", "a");
10191       emitLabel (tlbl1);
10192       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10193       popB (pushedB);
10194       aopPut (result, "a", 0);
10195       goto release;
10196     }
10197
10198   reAdjustPreg (AOP (result));
10199   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10200   emitLabel (tlbl);
10201   emitcode ("mov", "c,ov");
10202   _startLazyDPSEvaluation ();
10203   while (size--)
10204     {
10205       l = aopGet (result, offset, FALSE, FALSE, NULL);
10206       MOVA (l);
10207       emitcode ("rrc", "a");
10208       aopPut (result, "a", offset--);
10209     }
10210   _endLazyDPSEvaluation ();
10211   reAdjustPreg (AOP (result));
10212   emitLabel (tlbl1);
10213   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10214   popB (pushedB);
10215
10216 release:
10217   freeAsmop (result, NULL, ic, TRUE);
10218   freeAsmop (left, NULL, ic, TRUE);
10219 }
10220
10221 /*-----------------------------------------------------------------*/
10222 /* genRightShift - generate code for right shifting                */
10223 /*-----------------------------------------------------------------*/
10224 static void
10225 genRightShift (iCode * ic)
10226 {
10227   operand *right, *left, *result;
10228   sym_link *letype;
10229   int size, offset;
10230   char *l;
10231   symbol *tlbl, *tlbl1;
10232   bool pushedB;
10233
10234   D (emitcode (";", "genRightShift"));
10235
10236   /* if signed then we do it the hard way preserve the
10237      sign bit moving it inwards */
10238   letype = getSpec (operandType (IC_LEFT (ic)));
10239
10240   if (!SPEC_USIGN (letype))
10241     {
10242       genSignedRightShift (ic);
10243       return;
10244     }
10245
10246   /* signed & unsigned types are treated the same : i.e. the
10247      signed is NOT propagated inwards : quoting from the
10248      ANSI - standard : "for E1 >> E2, is equivalent to division
10249      by 2**E2 if unsigned or if it has a non-negative value,
10250      otherwise the result is implementation defined ", MY definition
10251      is that the sign does not get propagated */
10252
10253   right = IC_RIGHT (ic);
10254   left = IC_LEFT (ic);
10255   result = IC_RESULT (ic);
10256
10257   aopOp (right, ic, FALSE, FALSE);
10258
10259 #ifdef BETTER_LITERAL_SHIFT
10260   /* if the shift count is known then do it
10261      as efficiently as possible */
10262   if (AOP_TYPE (right) == AOP_LIT)
10263     {
10264       if (genRightShiftLiteral (left, right, result, ic, 0))
10265       {
10266         return;
10267       }
10268     }
10269 #endif
10270
10271   /* shift count is unknown then we have to form
10272      a loop get the loop count in B : Note: we take
10273      only the lower order byte since shifting
10274      more that 32 bits make no sense anyway, ( the
10275      largest size of an object can be only 32 bits ) */
10276
10277   pushedB = pushB ();
10278   if (AOP_TYPE (right) == AOP_LIT)
10279   {
10280       /* Really should be handled by genRightShiftLiteral,
10281        * but since I'm too lazy to fix that today, at least we can make
10282        * some small improvement.
10283        */
10284        emitcode("mov", "b,#!constbyte",
10285                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10286   }
10287   else
10288   {
10289       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10290       emitcode ("inc", "b");
10291   }
10292   freeAsmop (right, NULL, ic, TRUE);
10293   aopOp (left, ic, FALSE, FALSE);
10294   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10295
10296   /* now move the left to the result if they are not the
10297      same */
10298   if (!sameRegs (AOP (left), AOP (result)) &&
10299       AOP_SIZE (result) > 1)
10300     {
10301       size = AOP_SIZE (result);
10302       offset = 0;
10303       _startLazyDPSEvaluation ();
10304       while (size--)
10305         {
10306           l = aopGet (left, offset, FALSE, TRUE, NULL);
10307           if (*l == '@' && IS_AOP_PREG (result))
10308             {
10309
10310               emitcode ("mov", "a,%s", l);
10311               aopPut (result, "a", offset);
10312             }
10313           else
10314             aopPut (result, l, offset);
10315           offset++;
10316         }
10317       _endLazyDPSEvaluation ();
10318     }
10319
10320   tlbl = newiTempLabel (NULL);
10321   tlbl1 = newiTempLabel (NULL);
10322   size = AOP_SIZE (result);
10323   offset = size - 1;
10324
10325   /* if it is only one byte then */
10326   if (size == 1)
10327     {
10328       l = aopGet (left, 0, FALSE, FALSE, NULL);
10329       MOVA (l);
10330       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10331       emitLabel (tlbl);
10332       CLRC;
10333       emitcode ("rrc", "a");
10334       emitLabel (tlbl1);
10335       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10336       popB (pushedB);
10337       aopPut (result, "a", 0);
10338       goto release;
10339     }
10340
10341   reAdjustPreg (AOP (result));
10342   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10343   emitLabel (tlbl);
10344   CLRC;
10345   _startLazyDPSEvaluation ();
10346   while (size--)
10347     {
10348       l = aopGet (result, offset, FALSE, FALSE, NULL);
10349       MOVA (l);
10350       emitcode ("rrc", "a");
10351       aopPut (result, "a", offset--);
10352     }
10353   _endLazyDPSEvaluation ();
10354   reAdjustPreg (AOP (result));
10355
10356   emitLabel (tlbl1);
10357   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10358   popB (pushedB);
10359
10360 release:
10361   freeAsmop (result, NULL, ic, TRUE);
10362   freeAsmop (left, NULL, ic, TRUE);
10363 }
10364
10365 /*-----------------------------------------------------------------*/
10366 /* emitPtrByteGet - emits code to get a byte into A through a      */
10367 /*                  pointer register (R0, R1, or DPTR). The        */
10368 /*                  original value of A can be preserved in B.     */
10369 /*-----------------------------------------------------------------*/
10370 static void
10371 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10372 {
10373   switch (p_type)
10374     {
10375     case IPOINTER:
10376     case POINTER:
10377       if (preserveAinB)
10378         emitcode ("mov", "b,a");
10379       emitcode ("mov", "a,@%s", rname);
10380       break;
10381
10382     case PPOINTER:
10383       if (preserveAinB)
10384         emitcode ("mov", "b,a");
10385       emitcode ("movx", "a,@%s", rname);
10386       break;
10387
10388     case FPOINTER:
10389       if (preserveAinB)
10390         emitcode ("mov", "b,a");
10391       emitcode ("movx", "a,@dptr");
10392       break;
10393
10394     case CPOINTER:
10395       if (preserveAinB)
10396         emitcode ("mov", "b,a");
10397       emitcode ("clr", "a");
10398       emitcode ("movc", "a,@a+dptr");
10399       break;
10400
10401     case GPOINTER:
10402       if (preserveAinB)
10403         {
10404           emitcode ("push", "b");
10405           emitcode ("push", "acc");
10406         }
10407       emitcode ("lcall", "__gptrget");
10408       if (preserveAinB)
10409         emitcode ("pop", "b");
10410       break;
10411     }
10412 }
10413
10414 /*-----------------------------------------------------------------*/
10415 /* emitPtrByteSet - emits code to set a byte from src through a    */
10416 /*                  pointer register (R0, R1, or DPTR).            */
10417 /*-----------------------------------------------------------------*/
10418 static void
10419 emitPtrByteSet (char *rname, int p_type, char *src)
10420 {
10421   switch (p_type)
10422     {
10423     case IPOINTER:
10424     case POINTER:
10425       if (*src=='@')
10426         {
10427           MOVA (src);
10428           emitcode ("mov", "@%s,a", rname);
10429         }
10430       else
10431         emitcode ("mov", "@%s,%s", rname, src);
10432       break;
10433
10434     case PPOINTER:
10435       MOVA (src);
10436       emitcode ("movx", "@%s,a", rname);
10437       break;
10438
10439     case FPOINTER:
10440       MOVA (src);
10441       emitcode ("movx", "@dptr,a");
10442       break;
10443
10444     case GPOINTER:
10445       MOVA (src);
10446       emitcode ("lcall", "__gptrput");
10447       break;
10448     }
10449 }
10450
10451 /*-----------------------------------------------------------------*/
10452 /* genUnpackBits - generates code for unpacking bits               */
10453 /*-----------------------------------------------------------------*/
10454 static void
10455 genUnpackBits (operand * result, char *rname, int ptype)
10456 {
10457   int offset = 0;       /* result byte offset */
10458   int rsize;            /* result size */
10459   int rlen = 0;         /* remaining bitfield length */
10460   sym_link *etype;      /* bitfield type information */
10461   int blen;             /* bitfield length */
10462   int bstr;             /* bitfield starting bit within byte */
10463
10464   D(emitcode (";", "genUnpackBits"));
10465
10466   etype = getSpec (operandType (result));
10467   rsize = getSize (operandType (result));
10468   blen = SPEC_BLEN (etype);
10469   bstr = SPEC_BSTR (etype);
10470
10471   /* If the bitfield length is less than a byte */
10472   if (blen < 8)
10473     {
10474       emitPtrByteGet (rname, ptype, FALSE);
10475       AccRol (8 - bstr);
10476       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10477       if (!SPEC_USIGN (etype))
10478         {
10479           /* signed bitfield */
10480           symbol *tlbl = newiTempLabel (NULL);
10481
10482           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10483           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10484           emitLabel (tlbl);
10485         }
10486       aopPut (result, "a", offset++);
10487       goto finish;
10488     }
10489
10490   /* Bit field did not fit in a byte. Copy all
10491      but the partial byte at the end.  */
10492   for (rlen=blen;rlen>=8;rlen-=8)
10493     {
10494       emitPtrByteGet (rname, ptype, FALSE);
10495       aopPut (result, "a", offset++);
10496       if (rlen>8)
10497         emitcode ("inc", "%s", rname);
10498     }
10499
10500   /* Handle the partial byte at the end */
10501   if (rlen)
10502     {
10503       emitPtrByteGet (rname, ptype, FALSE);
10504       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10505       if (!SPEC_USIGN (etype))
10506         {
10507           /* signed bitfield */
10508           symbol *tlbl = newiTempLabel (NULL);
10509
10510           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10511           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10512           emitLabel (tlbl);
10513         }
10514       aopPut (result, "a", offset++);
10515     }
10516
10517 finish:
10518   if (offset < rsize)
10519     {
10520       char *source;
10521
10522       if (SPEC_USIGN (etype))
10523         source = zero;
10524       else
10525         {
10526           /* signed bitfield: sign extension with 0x00 or 0xff */
10527           emitcode ("rlc", "a");
10528           emitcode ("subb", "a,acc");
10529
10530           source = "a";
10531         }
10532       rsize -= offset;
10533       while (rsize--)
10534         aopPut (result, source, offset++);
10535     }
10536 }
10537
10538
10539 /*-----------------------------------------------------------------*/
10540 /* genDataPointerGet - generates code when ptr offset is known     */
10541 /*-----------------------------------------------------------------*/
10542 static void
10543 genDataPointerGet (operand * left,
10544                    operand * result,
10545                    iCode * ic)
10546 {
10547   char *l;
10548   char buffer[256];
10549   int size, offset = 0;
10550   aopOp (result, ic, TRUE, FALSE);
10551
10552   /* get the string representation of the name */
10553   l = aopGet (left, 0, FALSE, TRUE, NULL);
10554   size = AOP_SIZE (result);
10555   _startLazyDPSEvaluation ();
10556   while (size--)
10557     {
10558       if (offset)
10559         {
10560           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
10561         }
10562       else
10563         {
10564           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
10565         }
10566       aopPut (result, buffer, offset++);
10567     }
10568   _endLazyDPSEvaluation ();
10569
10570   freeAsmop (result, NULL, ic, TRUE);
10571   freeAsmop (left, NULL, ic, TRUE);
10572 }
10573
10574 /*-----------------------------------------------------------------*/
10575 /* genNearPointerGet - emitcode for near pointer fetch             */
10576 /*-----------------------------------------------------------------*/
10577 static void
10578 genNearPointerGet (operand * left,
10579                    operand * result,
10580                    iCode * ic,
10581                    iCode *pi)
10582 {
10583   asmop *aop = NULL;
10584   regs *preg;
10585   char *rname;
10586   sym_link *rtype, *retype, *letype;
10587   sym_link *ltype = operandType (left);
10588   char buffer[80];
10589
10590   rtype = operandType (result);
10591   retype = getSpec (rtype);
10592   letype = getSpec (ltype);
10593
10594   aopOp (left, ic, FALSE, FALSE);
10595
10596   /* if left is rematerialisable and
10597      result is not bitfield variable type and
10598      the left is pointer to data space i.e
10599      lower 128 bytes of space */
10600   if (AOP_TYPE (left) == AOP_IMMD &&
10601       !IS_BITFIELD (retype) &&
10602       !IS_BITFIELD (letype) &&
10603       DCL_TYPE (ltype) == POINTER)
10604     {
10605       genDataPointerGet (left, result, ic);
10606       return;
10607     }
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, DP2_RESULT_REG));
10619       rname = preg->name;
10620     }
10621   else
10622     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
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, POINTER);
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           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10639             {
10640
10641               emitcode ("mov", "a,@%s", rname);
10642               aopPut (result, "a", offset);
10643             }
10644           else
10645             {
10646               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10647               aopPut (result, buffer, offset);
10648             }
10649           offset++;
10650           if (size || pi)
10651             emitcode ("inc", "%s", rname);
10652         }
10653     }
10654
10655   /* now some housekeeping stuff */
10656   if (aop)      /* we had to allocate for this iCode */
10657     {
10658       if (pi) { /* post increment present */
10659         aopPut (left, rname, 0);
10660       }
10661       freeAsmop (NULL, aop, ic, TRUE);
10662     }
10663   else
10664     {
10665       /* we did not allocate which means left
10666          already in a pointer register, then
10667          if size > 0 && this could be used again
10668          we have to point it back to where it
10669          belongs */
10670       if (AOP_SIZE (result) > 1 &&
10671           !OP_SYMBOL (left)->remat &&
10672           (OP_SYMBOL (left)->liveTo > ic->seq ||
10673            ic->depth) &&
10674           !pi)
10675         {
10676           int size = AOP_SIZE (result) - 1;
10677           while (size--)
10678             emitcode ("dec", "%s", rname);
10679         }
10680     }
10681
10682   /* done */
10683   freeAsmop (result, NULL, ic, TRUE);
10684   if (pi) pi->generated = 1;
10685 }
10686
10687 /*-----------------------------------------------------------------*/
10688 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10689 /*-----------------------------------------------------------------*/
10690 static void
10691 genPagedPointerGet (operand * left,
10692                     operand * result,
10693                     iCode * ic,
10694                     iCode * pi)
10695 {
10696   asmop *aop = NULL;
10697   regs *preg;
10698   char *rname;
10699   sym_link *rtype, *retype, *letype;
10700
10701   rtype = operandType (result);
10702   retype = getSpec (rtype);
10703   letype = getSpec (operandType (left));
10704   aopOp (left, ic, FALSE, FALSE);
10705
10706   /* if the value is already in a pointer register
10707      then don't need anything more */
10708   if (!AOP_INPREG (AOP (left)))
10709     {
10710       /* otherwise get a free pointer register */
10711       aop = newAsmop (0);
10712       preg = getFreePtr (ic, &aop, FALSE);
10713       emitcode ("mov", "%s,%s",
10714                 preg->name,
10715                 aopGet (left, 0, FALSE, TRUE, NULL));
10716       rname = preg->name;
10717     }
10718   else
10719     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10720
10721   freeAsmop (left, NULL, ic, TRUE);
10722   aopOp (result, ic, FALSE, FALSE);
10723
10724   /* if bitfield then unpack the bits */
10725   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10726     genUnpackBits (result, rname, PPOINTER);
10727   else
10728     {
10729       /* we have can just get the values */
10730       int size = AOP_SIZE (result);
10731       int offset = 0;
10732
10733       while (size--)
10734         {
10735
10736           emitcode ("movx", "a,@%s", rname);
10737           aopPut (result, "a", offset);
10738
10739           offset++;
10740
10741           if (size || pi)
10742             emitcode ("inc", "%s", rname);
10743         }
10744     }
10745
10746   /* now some housekeeping stuff */
10747   if (aop)      /* we had to allocate for this iCode */
10748     {
10749       if (pi)
10750         aopPut (left, rname, 0);
10751       freeAsmop (NULL, aop, ic, TRUE);
10752     }
10753   else
10754     {
10755       /* we did not allocate which means left
10756          already in a pointer register, then
10757          if size > 0 && this could be used again
10758          we have to point it back to where it
10759          belongs */
10760       if (AOP_SIZE (result) > 1 &&
10761           !OP_SYMBOL (left)->remat &&
10762           (OP_SYMBOL (left)->liveTo > ic->seq ||
10763            ic->depth) &&
10764           !pi)
10765         {
10766           int size = AOP_SIZE (result) - 1;
10767           while (size--)
10768             emitcode ("dec", "%s", rname);
10769         }
10770     }
10771
10772   /* done */
10773   freeAsmop (result, NULL, ic, TRUE);
10774   if (pi) pi->generated = 1;
10775 }
10776
10777 /*-----------------------------------------------------------------*/
10778 /* genFarPointerGet - get value from far space                     */
10779 /*-----------------------------------------------------------------*/
10780 static void
10781 genFarPointerGet (operand * left,
10782                   operand * result, iCode * ic, iCode *pi)
10783 {
10784   int size, offset, dopi=1;
10785   sym_link *retype = getSpec (operandType (result));
10786   sym_link *letype = getSpec (operandType (left));
10787   D (emitcode (";", "genFarPointerGet"););
10788
10789   aopOp (left, ic, FALSE, FALSE);
10790
10791   /* if the operand is already in dptr
10792      then we do nothing else we move the value to dptr */
10793   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10794     {
10795       /* if this is rematerializable */
10796       if (AOP_TYPE (left) == AOP_IMMD)
10797         {
10798           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10799         }
10800       else
10801         {
10802           /* we need to get it byte by byte */
10803           _startLazyDPSEvaluation ();
10804           if (AOP_TYPE (left) != AOP_DPTR)
10805             {
10806               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10807               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10808               if (options.model == MODEL_FLAT24)
10809                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10810             }
10811           else
10812             {
10813               /* We need to generate a load to DPTR indirect through DPTR. */
10814               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10815               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10816               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10817               if (options.model == MODEL_FLAT24)
10818                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10819               emitcode ("pop", "dph");
10820               emitcode ("pop", "dpl");
10821               dopi =0;
10822             }
10823           _endLazyDPSEvaluation ();
10824         }
10825     }
10826   /* so dptr now contains the address */
10827   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10828
10829   /* if bit then unpack */
10830   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10831       if (AOP_INDPTRn(left)) {
10832           genSetDPTR(AOP(left)->aopu.dptr);
10833       }
10834       genUnpackBits (result, "dptr", FPOINTER);
10835       if (AOP_INDPTRn(left)) {
10836           genSetDPTR(0);
10837       }
10838   } else
10839     {
10840       size = AOP_SIZE (result);
10841       offset = 0;
10842
10843       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10844           while (size--) {
10845               genSetDPTR(AOP(left)->aopu.dptr);
10846               emitcode ("movx", "a,@dptr");
10847               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10848                   emitcode ("inc", "dptr");
10849               genSetDPTR (0);
10850               aopPut (result, "a", offset++);
10851           }
10852       } else {
10853           _startLazyDPSEvaluation ();
10854           while (size--) {
10855               if (AOP_INDPTRn(left)) {
10856                   genSetDPTR(AOP(left)->aopu.dptr);
10857               } else {
10858                   genSetDPTR (0);
10859               }
10860               _flushLazyDPS ();
10861
10862               emitcode ("movx", "a,@dptr");
10863               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10864                   emitcode ("inc", "dptr");
10865
10866               aopPut (result, "a", offset++);
10867           }
10868           _endLazyDPSEvaluation ();
10869       }
10870     }
10871   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10872       if (!AOP_INDPTRn(left)) {
10873           _startLazyDPSEvaluation ();
10874           aopPut (left, "dpl", 0);
10875           aopPut (left, "dph", 1);
10876           if (options.model == MODEL_FLAT24)
10877               aopPut (left, "dpx", 2);
10878           _endLazyDPSEvaluation ();
10879       }
10880     pi->generated = 1;
10881   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10882              AOP_SIZE(result) > 1 &&
10883              IS_SYMOP(left) &&
10884              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10885
10886       size = AOP_SIZE (result) - 1;
10887       if (AOP_INDPTRn(left)) {
10888           genSetDPTR(AOP(left)->aopu.dptr);
10889       }
10890       while (size--) emitcode ("lcall","__decdptr");
10891       if (AOP_INDPTRn(left)) {
10892           genSetDPTR(0);
10893       }
10894   }
10895
10896   freeAsmop (result, NULL, ic, TRUE);
10897   freeAsmop (left, NULL, ic, TRUE);
10898 }
10899
10900 /*-----------------------------------------------------------------*/
10901 /* genCodePointerGet - get value from code space                   */
10902 /*-----------------------------------------------------------------*/
10903 static void
10904 genCodePointerGet (operand * left,
10905                     operand * result, iCode * ic, iCode *pi)
10906 {
10907   int size, offset, dopi=1;
10908   sym_link *retype = getSpec (operandType (result));
10909
10910   aopOp (left, ic, FALSE, FALSE);
10911
10912   /* if the operand is already in dptr
10913      then we do nothing else we move the value to dptr */
10914   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10915     {
10916       /* if this is rematerializable */
10917       if (AOP_TYPE (left) == AOP_IMMD)
10918         {
10919           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10920         }
10921       else
10922         {                       /* we need to get it byte by byte */
10923           _startLazyDPSEvaluation ();
10924           if (AOP_TYPE (left) != AOP_DPTR)
10925             {
10926               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10927               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10928               if (options.model == MODEL_FLAT24)
10929                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10930             }
10931           else
10932             {
10933               /* We need to generate a load to DPTR indirect through DPTR. */
10934               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10935               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10936               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10937               if (options.model == MODEL_FLAT24)
10938                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10939               emitcode ("pop", "dph");
10940               emitcode ("pop", "dpl");
10941               dopi=0;
10942             }
10943           _endLazyDPSEvaluation ();
10944         }
10945     }
10946   /* so dptr now contains the address */
10947   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10948
10949   /* if bit then unpack */
10950   if (IS_BITFIELD (retype)) {
10951       if (AOP_INDPTRn(left)) {
10952           genSetDPTR(AOP(left)->aopu.dptr);
10953       }
10954       genUnpackBits (result, "dptr", CPOINTER);
10955       if (AOP_INDPTRn(left)) {
10956           genSetDPTR(0);
10957       }
10958   } else
10959     {
10960       size = AOP_SIZE (result);
10961       offset = 0;
10962       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10963           while (size--) {
10964               genSetDPTR(AOP(left)->aopu.dptr);
10965               emitcode ("clr", "a");
10966               emitcode ("movc", "a,@a+dptr");
10967               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10968                   emitcode ("inc", "dptr");
10969               genSetDPTR (0);
10970               aopPut (result, "a", offset++);
10971           }
10972       } else {
10973           _startLazyDPSEvaluation ();
10974           while (size--)
10975               {
10976                   if (AOP_INDPTRn(left)) {
10977                       genSetDPTR(AOP(left)->aopu.dptr);
10978                   } else {
10979                       genSetDPTR (0);
10980                   }
10981                   _flushLazyDPS ();
10982
10983                   emitcode ("clr", "a");
10984                   emitcode ("movc", "a,@a+dptr");
10985                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10986                       emitcode ("inc", "dptr");
10987                   aopPut (result, "a", offset++);
10988               }
10989           _endLazyDPSEvaluation ();
10990       }
10991     }
10992   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10993       if (!AOP_INDPTRn(left)) {
10994           _startLazyDPSEvaluation ();
10995
10996           aopPut (left, "dpl", 0);
10997           aopPut (left, "dph", 1);
10998           if (options.model == MODEL_FLAT24)
10999               aopPut (left, "dpx", 2);
11000
11001           _endLazyDPSEvaluation ();
11002       }
11003       pi->generated = 1;
11004   } else if (IS_SYMOP(left) &&
11005              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
11006              AOP_SIZE(result) > 1 &&
11007              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11008
11009       size = AOP_SIZE (result) - 1;
11010       if (AOP_INDPTRn(left)) {
11011           genSetDPTR(AOP(left)->aopu.dptr);
11012       }
11013       while (size--) emitcode ("lcall","__decdptr");
11014       if (AOP_INDPTRn(left)) {
11015           genSetDPTR(0);
11016       }
11017   }
11018
11019   freeAsmop (result, NULL, ic, TRUE);
11020   freeAsmop (left, NULL, ic, TRUE);
11021 }
11022
11023 /*-----------------------------------------------------------------*/
11024 /* genGenPointerGet - get value from generic pointer space         */
11025 /*-----------------------------------------------------------------*/
11026 static void
11027 genGenPointerGet (operand * left,
11028                   operand * result, iCode * ic, iCode * pi)
11029 {
11030   int size, offset;
11031   bool pushedB;
11032   sym_link *retype = getSpec (operandType (result));
11033   sym_link *letype = getSpec (operandType (left));
11034
11035   D (emitcode (";", "genGenPointerGet"));
11036
11037   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
11038
11039   pushedB = pushB ();
11040   /* if the operand is already in dptr
11041      then we do nothing else we move the value to dptr */
11042   if (AOP_TYPE (left) != AOP_STR)
11043     {
11044       /* if this is rematerializable */
11045       if (AOP_TYPE (left) == AOP_IMMD)
11046         {
11047           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
11048           if (AOP(left)->aopu.aop_immd.from_cast_remat)
11049             {
11050               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
11051             }
11052           else
11053             {
11054               emitcode ("mov", "b,#%d", pointerCode (retype));
11055             }
11056         }
11057       else
11058         {                       /* we need to get it byte by byte */
11059           _startLazyDPSEvaluation ();
11060           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
11061           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
11062           if (options.model == MODEL_FLAT24) {
11063               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
11064               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
11065           } else {
11066               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
11067           }
11068           _endLazyDPSEvaluation ();
11069         }
11070     }
11071
11072   /* so dptr-b now contains the address */
11073   aopOp (result, ic, FALSE, TRUE);
11074
11075   /* if bit then unpack */
11076   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11077     {
11078       genUnpackBits (result, "dptr", GPOINTER);
11079     }
11080   else
11081     {
11082       size = AOP_SIZE (result);
11083       offset = 0;
11084
11085       while (size--)
11086         {
11087           if (size)
11088             {
11089                 // Get two bytes at a time, results in _AP & A.
11090                 // dptr will be incremented ONCE by __gptrgetWord.
11091                 //
11092                 // Note: any change here must be coordinated
11093                 // with the implementation of __gptrgetWord
11094                 // in device/lib/_gptrget.c
11095                 emitcode ("lcall", "__gptrgetWord");
11096                 aopPut (result, "a", offset++);
11097                 aopPut (result, DP2_RESULT_REG, offset++);
11098                 size--;
11099             }
11100           else
11101             {
11102                 // Only one byte to get.
11103                 emitcode ("lcall", "__gptrget");
11104                 aopPut (result, "a", offset++);
11105             }
11106
11107           if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11108             {
11109                 emitcode ("inc", "dptr");
11110             }
11111         }
11112     }
11113
11114   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11115     _startLazyDPSEvaluation ();
11116
11117     aopPut (left, "dpl", 0);
11118     aopPut (left, "dph", 1);
11119     if (options.model == MODEL_FLAT24) {
11120         aopPut (left, "dpx", 2);
11121         aopPut (left, "b", 3);
11122     } else  aopPut (left, "b", 2);
11123
11124     _endLazyDPSEvaluation ();
11125
11126     pi->generated = 1;
11127   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11128              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11129
11130       size = AOP_SIZE (result) - 1;
11131       while (size--) emitcode ("lcall","__decdptr");
11132   }
11133   popB (pushedB);
11134
11135   freeAsmop (result, NULL, ic, TRUE);
11136   freeAsmop (left, NULL, ic, TRUE);
11137 }
11138
11139 /*-----------------------------------------------------------------*/
11140 /* genPointerGet - generate code for pointer get                   */
11141 /*-----------------------------------------------------------------*/
11142 static void
11143 genPointerGet (iCode * ic, iCode *pi)
11144 {
11145   operand *left, *result;
11146   sym_link *type, *etype;
11147   int p_type;
11148
11149   D (emitcode (";", "genPointerGet"));
11150
11151   left = IC_LEFT (ic);
11152   result = IC_RESULT (ic);
11153
11154   /* depending on the type of pointer we need to
11155      move it to the correct pointer register */
11156   type = operandType (left);
11157   etype = getSpec (type);
11158   /* if left is of type of pointer then it is simple */
11159   if (IS_PTR (type) && !IS_FUNC (type->next))
11160     {
11161       p_type = DCL_TYPE (type);
11162     }
11163   else
11164     {
11165       /* we have to go by the storage class */
11166       p_type = PTR_TYPE (SPEC_OCLS (etype));
11167     }
11168
11169   /* special case when cast remat */
11170   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11171       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11172     {
11173       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11174       type = operandType (left);
11175       p_type = DCL_TYPE (type);
11176     }
11177   /* now that we have the pointer type we assign
11178      the pointer values */
11179   switch (p_type)
11180     {
11181
11182     case POINTER:
11183     case IPOINTER:
11184       genNearPointerGet (left, result, ic, pi);
11185       break;
11186
11187     case PPOINTER:
11188       genPagedPointerGet (left, result, ic, pi);
11189       break;
11190
11191     case FPOINTER:
11192       genFarPointerGet (left, result, ic, pi);
11193       break;
11194
11195     case CPOINTER:
11196       genCodePointerGet (left, result, ic, pi);
11197       break;
11198
11199     case GPOINTER:
11200       genGenPointerGet (left, result, ic, pi);
11201       break;
11202     }
11203 }
11204
11205
11206 /*-----------------------------------------------------------------*/
11207 /* genPackBits - generates code for packed bit storage             */
11208 /*-----------------------------------------------------------------*/
11209 static void
11210 genPackBits (sym_link * etype,
11211              operand * right,
11212              char *rname, int p_type)
11213 {
11214   int offset = 0;       /* source byte offset */
11215   int rlen = 0;         /* remaining bitfield length */
11216   int blen;             /* bitfield length */
11217   int bstr;             /* bitfield starting bit within byte */
11218   int litval;           /* source literal value (if AOP_LIT) */
11219   unsigned char mask;   /* bitmask within current byte */
11220
11221   D(emitcode (";", "genPackBits"));
11222
11223   blen = SPEC_BLEN (etype);
11224   bstr = SPEC_BSTR (etype);
11225
11226   /* If the bitfield length is less than a byte */
11227   if (blen < 8)
11228     {
11229       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11230               (unsigned char) (0xFF >> (8 - bstr)));
11231
11232       if (AOP_TYPE (right) == AOP_LIT)
11233         {
11234           /* Case with a bitfield length <8 and literal source
11235           */
11236           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11237           litval <<= bstr;
11238           litval &= (~mask) & 0xff;
11239           emitPtrByteGet (rname, p_type, FALSE);
11240           if ((mask|litval)!=0xff)
11241             emitcode ("anl","a,#!constbyte", mask);
11242           if (litval)
11243             emitcode ("orl","a,#!constbyte", litval);
11244         }
11245       else
11246         {
11247           if ((blen==1) && (p_type!=GPOINTER))
11248             {
11249               /* Case with a bitfield length == 1 and no generic pointer
11250               */
11251               if (AOP_TYPE (right) == AOP_CRY)
11252                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11253               else
11254                 {
11255                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11256                   emitcode ("rrc","a");
11257                 }
11258               emitPtrByteGet (rname, p_type, FALSE);
11259               emitcode ("mov","acc.%d,c",bstr);
11260             }
11261           else
11262             {
11263               bool pushedB;
11264               /* Case with a bitfield length < 8 and arbitrary source
11265               */
11266               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11267               /* shift and mask source value */
11268               AccLsh (bstr);
11269               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11270
11271               pushedB = pushB ();
11272               /* transfer A to B and get next byte */
11273               emitPtrByteGet (rname, p_type, TRUE);
11274
11275               emitcode ("anl", "a,#!constbyte", mask);
11276               emitcode ("orl", "a,b");
11277               if (p_type == GPOINTER)
11278                 emitcode ("pop", "b");
11279
11280               popB (pushedB);
11281            }
11282         }
11283
11284       emitPtrByteSet (rname, p_type, "a");
11285       return;
11286     }
11287
11288   /* Bit length is greater than 7 bits. In this case, copy  */
11289   /* all except the partial byte at the end                 */
11290   for (rlen=blen;rlen>=8;rlen-=8)
11291     {
11292       emitPtrByteSet (rname, p_type,
11293                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11294       if (rlen>8)
11295         emitcode ("inc", "%s", rname);
11296     }
11297
11298   /* If there was a partial byte at the end */
11299   if (rlen)
11300     {
11301       mask = (((unsigned char) -1 << rlen) & 0xff);
11302
11303       if (AOP_TYPE (right) == AOP_LIT)
11304         {
11305           /* Case with partial byte and literal source
11306           */
11307           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11308           litval >>= (blen-rlen);
11309           litval &= (~mask) & 0xff;
11310           emitPtrByteGet (rname, p_type, FALSE);
11311           if ((mask|litval)!=0xff)
11312             emitcode ("anl","a,#!constbyte", mask);
11313           if (litval)
11314             emitcode ("orl","a,#!constbyte", litval);
11315         }
11316       else
11317         {
11318           bool pushedB;
11319           /* Case with partial byte and arbitrary source
11320           */
11321           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11322           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11323
11324           pushedB = pushB ();
11325           /* transfer A to B and get next byte */
11326           emitPtrByteGet (rname, p_type, TRUE);
11327
11328           emitcode ("anl", "a,#!constbyte", mask);
11329           emitcode ("orl", "a,b");
11330           if (p_type == GPOINTER)
11331             emitcode ("pop", "b");
11332
11333           popB (pushedB);
11334         }
11335       emitPtrByteSet (rname, p_type, "a");
11336     }
11337 }
11338
11339
11340 /*-----------------------------------------------------------------*/
11341 /* genDataPointerSet - remat pointer to data space                 */
11342 /*-----------------------------------------------------------------*/
11343 static void
11344 genDataPointerSet (operand * right,
11345                    operand * result,
11346                    iCode * ic)
11347 {
11348   int size, offset = 0;
11349   char *l, buffer[256];
11350
11351   D (emitcode (";", "genDataPointerSet"));
11352
11353   aopOp (right, ic, FALSE, FALSE);
11354
11355   l = aopGet (result, 0, FALSE, TRUE, NULL);
11356   size = AOP_SIZE (right);
11357   while (size--)
11358     {
11359       if (offset)
11360         SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11361       else
11362         SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11363       emitcode ("mov", "%s,%s", buffer,
11364                 aopGet (right, offset++, FALSE, FALSE, NULL));
11365     }
11366
11367   freeAsmop (right, NULL, ic, TRUE);
11368   freeAsmop (result, NULL, ic, TRUE);
11369 }
11370
11371 /*-----------------------------------------------------------------*/
11372 /* genNearPointerSet - emitcode for near pointer put               */
11373 /*-----------------------------------------------------------------*/
11374 static void
11375 genNearPointerSet (operand * right,
11376                    operand * result,
11377                    iCode * ic,
11378                    iCode * pi)
11379 {
11380   asmop *aop = NULL;
11381   char *rname, *l;
11382   sym_link *retype, *letype;
11383   sym_link *ptype = operandType (result);
11384
11385   D (emitcode (";", "genNearPointerSet"));
11386
11387   retype = getSpec (operandType (right));
11388   letype = getSpec (ptype);
11389
11390   aopOp (result, ic, FALSE, FALSE);
11391
11392   /* if the result is rematerializable &
11393      in data space & not a bit variable */
11394   if (AOP_TYPE (result) == AOP_IMMD &&
11395       DCL_TYPE (ptype) == POINTER &&
11396       !IS_BITVAR (retype) &&
11397       !IS_BITVAR (letype))
11398     {
11399       genDataPointerSet (right, result, ic);
11400       return;
11401     }
11402
11403   /* if the value is already in a pointer register
11404      then don't need anything more */
11405   if (!AOP_INPREG (AOP (result)))
11406     {
11407       /* otherwise get a free pointer register */
11408       regs *preg;
11409
11410       aop = newAsmop (0);
11411       preg = getFreePtr (ic, &aop, FALSE);
11412       emitcode ("mov", "%s,%s",
11413                 preg->name,
11414                 aopGet (result, 0, FALSE, TRUE, NULL));
11415       rname = preg->name;
11416     }
11417   else
11418     {
11419       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11420     }
11421
11422   aopOp (right, ic, FALSE, FALSE);
11423
11424   /* if bitfield then unpack the bits */
11425   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11426     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11427   else
11428     {
11429       /* we can just get the values */
11430       int size = AOP_SIZE (right);
11431       int offset = 0;
11432
11433       while (size--)
11434         {
11435           l = aopGet (right, offset, FALSE, TRUE, NULL);
11436           if ((*l == '@') || (strcmp (l, "acc") == 0))
11437             {
11438               MOVA (l);
11439               emitcode ("mov", "@%s,a", rname);
11440             }
11441           else
11442             emitcode ("mov", "@%s,%s", rname, l);
11443           if (size || pi)
11444             emitcode ("inc", "%s", rname);
11445           offset++;
11446         }
11447     }
11448
11449   /* now some housekeeping stuff */
11450   if (aop)      /* we had to allocate for this iCode */
11451     {
11452       if (pi)
11453         aopPut (result, rname, 0);
11454       freeAsmop (NULL, aop, ic, TRUE);
11455     }
11456   else
11457     {
11458       /* we did not allocate which means left
11459          already in a pointer register, then
11460          if size > 0 && this could be used again
11461          we have to point it back to where it
11462          belongs */
11463       if (AOP_SIZE (right) > 1 &&
11464           !OP_SYMBOL (result)->remat &&
11465           (OP_SYMBOL (result)->liveTo > ic->seq ||
11466            ic->depth) &&
11467           !pi)
11468         {
11469           int size = AOP_SIZE (right) - 1;
11470           while (size--)
11471             emitcode ("dec", "%s", rname);
11472         }
11473     }
11474
11475   /* done */
11476   if (pi)
11477     pi->generated = 1;
11478   freeAsmop (right, NULL, ic, TRUE);
11479   freeAsmop (result, NULL, ic, TRUE);
11480 }
11481
11482 /*-----------------------------------------------------------------*/
11483 /* genPagedPointerSet - emitcode for Paged pointer put             */
11484 /*-----------------------------------------------------------------*/
11485 static void
11486 genPagedPointerSet (operand * right,
11487                     operand * result,
11488                     iCode * ic,
11489                     iCode * pi)
11490 {
11491   asmop *aop = NULL;
11492   char *rname, *l;
11493   sym_link *retype, *letype;
11494
11495   D (emitcode (";", "genPagedPointerSet"));
11496
11497   retype = getSpec (operandType (right));
11498   letype = getSpec (operandType (result));
11499
11500   aopOp (result, ic, FALSE, FALSE);
11501
11502   /* if the value is already in a pointer register
11503      then don't need anything more */
11504   if (!AOP_INPREG (AOP (result)))
11505     {
11506       /* otherwise get a free pointer register */
11507       regs *preg;
11508
11509       aop = newAsmop (0);
11510       preg = getFreePtr (ic, &aop, FALSE);
11511       emitcode ("mov", "%s,%s",
11512                 preg->name,
11513                 aopGet (result, 0, FALSE, TRUE, NULL));
11514       rname = preg->name;
11515     }
11516   else
11517     {
11518       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11519     }
11520
11521   aopOp (right, ic, FALSE, FALSE);
11522
11523   /* if bitfield then unpack the bits */
11524   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11525     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11526   else
11527     {
11528       /* we can just get the values */
11529       int size = AOP_SIZE (right);
11530       int offset = 0;
11531
11532       while (size--)
11533         {
11534           l = aopGet (right, offset, FALSE, TRUE, NULL);
11535           MOVA (l);
11536           emitcode ("movx", "@%s,a", rname);
11537           if (size || pi)
11538             emitcode ("inc", "%s", rname);
11539           offset++;
11540         }
11541     }
11542
11543   /* now some housekeeping stuff */
11544   if (aop)
11545     {
11546       if (pi)
11547         aopPut (result, rname, 0);
11548       /* we had to allocate for this iCode */
11549       freeAsmop (NULL, aop, ic, TRUE);
11550     }
11551   else
11552     {
11553       /* we did not allocate which means left
11554          already in a pointer register, then
11555          if size > 0 && this could be used again
11556          we have to point it back to where it
11557          belongs */
11558       if (AOP_SIZE (right) > 1 &&
11559           !OP_SYMBOL (result)->remat &&
11560           (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth) &&
11561           !pi)
11562         {
11563           int size = AOP_SIZE (right) - 1;
11564           while (size--)
11565             emitcode ("dec", "%s", rname);
11566         }
11567     }
11568
11569   /* done */
11570   if (pi)
11571     pi->generated = 1;
11572   freeAsmop (right, NULL, ic, TRUE);
11573   freeAsmop (result, NULL, ic, TRUE);
11574 }
11575
11576 /*-----------------------------------------------------------------*/
11577 /* genFarPointerSet - set value from far space                     */
11578 /*-----------------------------------------------------------------*/
11579 static void
11580 genFarPointerSet (operand * right,
11581                   operand * result, iCode * ic, iCode *pi)
11582 {
11583   int size, offset, dopi=1;
11584   sym_link *retype = getSpec (operandType (right));
11585   sym_link *letype = getSpec (operandType (result));
11586
11587   aopOp (result, ic, FALSE, FALSE);
11588
11589   /* if the operand is already in dptr
11590      then we do nothing else we move the value to dptr */
11591   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11592     {
11593       /* if this is remateriazable */
11594       if (AOP_TYPE (result) == AOP_IMMD)
11595         emitcode ("mov", "dptr,%s",
11596                   aopGet (result, 0, TRUE, FALSE, NULL));
11597       else
11598         {
11599           /* we need to get it byte by byte */
11600           _startLazyDPSEvaluation ();
11601           if (AOP_TYPE (result) != AOP_DPTR)
11602             {
11603               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11604               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11605               if (options.model == MODEL_FLAT24)
11606                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11607             }
11608           else
11609             {
11610               /* We need to generate a load to DPTR indirect through DPTR. */
11611               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11612
11613               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11614               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11615               if (options.model == MODEL_FLAT24)
11616                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11617               emitcode ("pop", "dph");
11618               emitcode ("pop", "dpl");
11619               dopi=0;
11620             }
11621           _endLazyDPSEvaluation ();
11622         }
11623     }
11624   /* so dptr now contains the address */
11625   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11626
11627   /* if bit then unpack */
11628   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11629   {
11630       if (AOP_INDPTRn(result)) {
11631           genSetDPTR(AOP(result)->aopu.dptr);
11632       }
11633       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11634       if (AOP_INDPTRn(result)) {
11635           genSetDPTR(0);
11636       }
11637   } else {
11638       size = AOP_SIZE (right);
11639       offset = 0;
11640       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11641           while (size--) {
11642               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11643
11644               genSetDPTR(AOP(result)->aopu.dptr);
11645               emitcode ("movx", "@dptr,a");
11646               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11647                   emitcode ("inc", "dptr");
11648               genSetDPTR (0);
11649           }
11650       } else {
11651           _startLazyDPSEvaluation ();
11652           while (size--) {
11653               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11654
11655               if (AOP_INDPTRn(result)) {
11656                   genSetDPTR(AOP(result)->aopu.dptr);
11657               } else {
11658                   genSetDPTR (0);
11659               }
11660               _flushLazyDPS ();
11661
11662               emitcode ("movx", "@dptr,a");
11663               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11664                   emitcode ("inc", "dptr");
11665           }
11666           _endLazyDPSEvaluation ();
11667       }
11668   }
11669
11670   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11671       if (!AOP_INDPTRn(result)) {
11672           _startLazyDPSEvaluation ();
11673
11674           aopPut (result,"dpl",0);
11675           aopPut (result,"dph",1);
11676           if (options.model == MODEL_FLAT24)
11677               aopPut (result,"dpx",2);
11678
11679           _endLazyDPSEvaluation ();
11680       }
11681       pi->generated=1;
11682   } else if (IS_SYMOP (result) &&
11683              (OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11684              AOP_SIZE(right) > 1 &&
11685              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11686
11687       size = AOP_SIZE (right) - 1;
11688       if (AOP_INDPTRn(result)) {
11689           genSetDPTR(AOP(result)->aopu.dptr);
11690       }
11691       while (size--) emitcode ("lcall","__decdptr");
11692       if (AOP_INDPTRn(result)) {
11693           genSetDPTR(0);
11694       }
11695   }
11696   freeAsmop (result, NULL, ic, TRUE);
11697   freeAsmop (right, NULL, ic, TRUE);
11698 }
11699
11700 /*-----------------------------------------------------------------*/
11701 /* genGenPointerSet - set value from generic pointer space         */
11702 /*-----------------------------------------------------------------*/
11703 static void
11704 genGenPointerSet (operand * right,
11705                   operand * result, iCode * ic, iCode * pi)
11706 {
11707   int size, offset;
11708   bool pushedB;
11709   sym_link *retype = getSpec (operandType (right));
11710   sym_link *letype = getSpec (operandType (result));
11711
11712   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11713
11714   pushedB = pushB ();
11715   /* if the operand is already in dptr
11716      then we do nothing else we move the value to dptr */
11717   if (AOP_TYPE (result) != AOP_STR)
11718     {
11719       _startLazyDPSEvaluation ();
11720       /* if this is remateriazable */
11721       if (AOP_TYPE (result) == AOP_IMMD)
11722         {
11723           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11724           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11725           {
11726               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11727           }
11728           else
11729           {
11730               emitcode ("mov",
11731                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11732           }
11733         }
11734       else
11735         {                       /* we need to get it byte by byte */
11736           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11737           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11738           if (options.model == MODEL_FLAT24) {
11739             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11740             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11741           } else {
11742             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11743           }
11744         }
11745       _endLazyDPSEvaluation ();
11746     }
11747   /* so dptr + b now contains the address */
11748   aopOp (right, ic, FALSE, TRUE);
11749
11750   /* if bit then unpack */
11751   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11752     {
11753       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11754     }
11755   else
11756     {
11757       size = AOP_SIZE (right);
11758       offset = 0;
11759
11760       _startLazyDPSEvaluation ();
11761       while (size--)
11762         {
11763           if (size)
11764             {
11765               // Set two bytes at a time, passed in _AP & A.
11766               // dptr will be incremented ONCE by __gptrputWord.
11767               //
11768               // Note: any change here must be coordinated
11769               // with the implementation of __gptrputWord
11770               // in device/lib/_gptrput.c
11771               emitcode("mov", "_ap, %s",
11772                        aopGet (right, offset++, FALSE, FALSE, NULL));
11773               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11774
11775               genSetDPTR (0);
11776               _flushLazyDPS ();
11777               emitcode ("lcall", "__gptrputWord");
11778               size--;
11779             }
11780           else
11781             {
11782               // Only one byte to put.
11783               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11784
11785               genSetDPTR (0);
11786               _flushLazyDPS ();
11787               emitcode ("lcall", "__gptrput");
11788             }
11789
11790           if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11791             {
11792               emitcode ("inc", "dptr");
11793             }
11794         }
11795       _endLazyDPSEvaluation ();
11796     }
11797
11798   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11799       _startLazyDPSEvaluation ();
11800
11801       aopPut (result, "dpl",0);
11802       aopPut (result, "dph",1);
11803       if (options.model == MODEL_FLAT24) {
11804           aopPut (result, "dpx",2);
11805           aopPut (result, "b",3);
11806       } else {
11807           aopPut (result, "b",2);
11808       }
11809       _endLazyDPSEvaluation ();
11810
11811       pi->generated=1;
11812   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11813              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11814
11815       size = AOP_SIZE (right) - 1;
11816       while (size--) emitcode ("lcall","__decdptr");
11817   }
11818   popB (pushedB);
11819
11820   freeAsmop (result, NULL, ic, TRUE);
11821   freeAsmop (right, NULL, ic, TRUE);
11822 }
11823
11824 /*-----------------------------------------------------------------*/
11825 /* genPointerSet - stores the value into a pointer location        */
11826 /*-----------------------------------------------------------------*/
11827 static void
11828 genPointerSet (iCode * ic, iCode *pi)
11829 {
11830   operand *right, *result;
11831   sym_link *type, *etype;
11832   int p_type;
11833
11834   D (emitcode (";", "genPointerSet"));
11835
11836   right = IC_RIGHT (ic);
11837   result = IC_RESULT (ic);
11838
11839   /* depending on the type of pointer we need to
11840      move it to the correct pointer register */
11841   type = operandType (result);
11842   etype = getSpec (type);
11843   /* if left is of type of pointer then it is simple */
11844   if (IS_PTR (type) && !IS_FUNC (type->next))
11845     {
11846       p_type = DCL_TYPE (type);
11847     }
11848   else
11849     {
11850       /* we have to go by the storage class */
11851       p_type = PTR_TYPE (SPEC_OCLS (etype));
11852     }
11853
11854   /* special case when cast remat */
11855   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11856       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11857           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11858           type = operandType (result);
11859           p_type = DCL_TYPE (type);
11860   }
11861
11862   /* now that we have the pointer type we assign
11863      the pointer values */
11864   switch (p_type)
11865     {
11866
11867     case POINTER:
11868     case IPOINTER:
11869       genNearPointerSet (right, result, ic, pi);
11870       break;
11871
11872     case PPOINTER:
11873       genPagedPointerSet (right, result, ic, pi);
11874       break;
11875
11876     case FPOINTER:
11877       genFarPointerSet (right, result, ic, pi);
11878       break;
11879
11880     case GPOINTER:
11881       genGenPointerSet (right, result, ic, pi);
11882       break;
11883
11884     default:
11885       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11886               "genPointerSet: illegal pointer type");
11887     }
11888 }
11889
11890 /*-----------------------------------------------------------------*/
11891 /* genIfx - generate code for Ifx statement                        */
11892 /*-----------------------------------------------------------------*/
11893 static void
11894 genIfx (iCode * ic, iCode * popIc)
11895 {
11896   operand *cond = IC_COND (ic);
11897   int isbit = 0;
11898   char *dup = NULL;
11899
11900   D (emitcode (";", "genIfx"));
11901
11902   aopOp (cond, ic, FALSE, FALSE);
11903
11904   /* get the value into acc */
11905   if (AOP_TYPE (cond) != AOP_CRY)
11906     {
11907       toBoolean (cond);
11908     }
11909   else
11910     {
11911       isbit = 1;
11912       if (AOP(cond)->aopu.aop_dir)
11913         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11914     }
11915
11916   /* the result is now in the accumulator or a directly addressable bit */
11917   freeAsmop (cond, NULL, ic, TRUE);
11918
11919   /* if the condition is a bit variable */
11920   if (isbit && dup)
11921     genIfxJump (ic, dup, popIc);
11922   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11923     genIfxJump (ic, SPIL_LOC (cond)->rname, popIc);
11924   else if (isbit && !IS_ITEMP (cond))
11925     genIfxJump (ic, OP_SYMBOL (cond)->rname, popIc);
11926   else
11927     genIfxJump (ic, "a", popIc);
11928
11929   ic->generated = 1;
11930 }
11931
11932 /*-----------------------------------------------------------------*/
11933 /* genAddrOf - generates code for address of                       */
11934 /*-----------------------------------------------------------------*/
11935 static void
11936 genAddrOf (iCode * ic)
11937 {
11938   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11939   int size, offset;
11940
11941   D (emitcode (";", "genAddrOf"));
11942
11943   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11944
11945   /* if the operand is on the stack then we
11946      need to get the stack offset of this
11947      variable */
11948   if (sym->onStack)
11949     {
11950       /* if 10 bit stack */
11951       if (options.stack10bit) {
11952           char buff[10];
11953           int  offset;
11954
11955           tsprintf(buff, sizeof(buff),
11956                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11957           /* if it has an offset then we need to compute it */
11958 /*        emitcode ("subb", "a,#!constbyte", */
11959 /*                  -((sym->stack < 0) ? */
11960 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11961 /*                    ((short) sym->stack)) & 0xff); */
11962 /*        emitcode ("mov","b,a"); */
11963 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11964 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11965 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11966           if (sym->stack) {
11967               emitcode ("mov", "a,_bpx");
11968               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11969                                              ((char) (sym->stack - _G.nRegsSaved)) :
11970                                              ((char) sym->stack )) & 0xff);
11971               emitcode ("mov", "b,a");
11972               emitcode ("mov", "a,_bpx+1");
11973
11974               offset = (((sym->stack < 0) ?
11975                          ((short) (sym->stack - _G.nRegsSaved)) :
11976                          ((short) sym->stack )) >> 8) & 0xff;
11977
11978               emitcode ("addc","a,#!constbyte", offset);
11979
11980               aopPut (IC_RESULT (ic), "b", 0);
11981               aopPut (IC_RESULT (ic), "a", 1);
11982               aopPut (IC_RESULT (ic), buff, 2);
11983           } else {
11984               /* we can just move _bp */
11985               aopPut (IC_RESULT (ic), "_bpx", 0);
11986               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11987               aopPut (IC_RESULT (ic), buff, 2);
11988           }
11989       } else {
11990           /* if it has an offset then we need to compute it */
11991           if (sym->stack)
11992             {
11993               emitcode ("mov", "a,_bp");
11994               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11995               aopPut (IC_RESULT (ic), "a", 0);
11996             }
11997           else
11998             {
11999               /* we can just move _bp */
12000               aopPut (IC_RESULT (ic), "_bp", 0);
12001             }
12002           /* fill the result with zero */
12003           size = AOP_SIZE (IC_RESULT (ic)) - 1;
12004
12005
12006           if (options.stack10bit && size < (FPTRSIZE - 1)) {
12007               fprintf (stderr,
12008                        "*** warning: pointer to stack var truncated.\n");
12009           }
12010
12011           offset = 1;
12012           while (size--)
12013             {
12014               aopPut (IC_RESULT (ic), zero, offset++);
12015             }
12016       }
12017       goto release;
12018     }
12019
12020   /* object not on stack then we need the name */
12021   size = getDataSize (IC_RESULT (ic));
12022   offset = 0;
12023
12024   while (size--)
12025     {
12026       char s[SDCC_NAME_MAX];
12027       if (offset)
12028         {
12029           switch (offset) {
12030           case 1:
12031               tsprintf(s, sizeof(s), "#!his",sym->rname);
12032               break;
12033           case 2:
12034               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
12035               break;
12036           case 3:
12037               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
12038               break;
12039           default: /* should not need this (just in case) */
12040               SNPRINTF (s, sizeof(s), "#(%s >> %d)", sym->rname, offset * 8);
12041           }
12042         }
12043       else
12044         {
12045           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
12046         }
12047       aopPut (IC_RESULT (ic), s, offset++);
12048     }
12049   if (opIsGptr (IC_RESULT (ic)))
12050     {
12051       char buffer[10];
12052       SNPRINTF (buffer, sizeof(buffer), "#0x%02x",
12053                 pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
12054       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
12055     }
12056
12057 release:
12058   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
12059
12060 }
12061
12062 #if 0 // obsolete, and buggy for != xdata
12063 /*-----------------------------------------------------------------*/
12064 /* genArrayInit - generates code for address of                    */
12065 /*-----------------------------------------------------------------*/
12066 static void
12067 genArrayInit (iCode * ic)
12068 {
12069     literalList *iLoop;
12070     int         ix, count;
12071     int         elementSize = 0, eIndex;
12072     unsigned    val, lastVal;
12073     sym_link    *type;
12074     operand     *left=IC_LEFT(ic);
12075
12076     D (emitcode (";", "genArrayInit"));
12077
12078     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
12079
12080     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
12081     {
12082         // Load immediate value into DPTR.
12083         emitcode("mov", "dptr, %s",
12084              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
12085     }
12086     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
12087     {
12088 #if 0
12089       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12090               "Unexpected operand to genArrayInit.\n");
12091       exit(1);
12092 #else
12093       // a regression because of SDCCcse.c:1.52
12094       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12095       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12096       if (options.model == MODEL_FLAT24)
12097         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12098 #endif
12099     }
12100
12101     type = operandType(IC_LEFT(ic));
12102
12103     if (type && type->next)
12104     {
12105         elementSize = getSize(type->next);
12106     }
12107     else
12108     {
12109         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12110                                 "can't determine element size in genArrayInit.\n");
12111         exit(1);
12112     }
12113
12114     iLoop = IC_ARRAYILIST(ic);
12115     lastVal = 0xffff;
12116
12117     while (iLoop)
12118     {
12119         bool firstpass = TRUE;
12120
12121         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12122                  iLoop->count, (int)iLoop->literalValue, elementSize);
12123
12124         ix = iLoop->count;
12125
12126         while (ix)
12127         {
12128             symbol *tlbl = NULL;
12129
12130             count = ix > 256 ? 256 : ix;
12131
12132             if (count > 1)
12133             {
12134                 tlbl = newiTempLabel (NULL);
12135                 if (firstpass || (count & 0xff))
12136                 {
12137                     emitcode("mov", "b, #!constbyte", count & 0xff);
12138                 }
12139
12140                 emitLabel (tlbl);
12141             }
12142
12143             firstpass = FALSE;
12144
12145             for (eIndex = 0; eIndex < elementSize; eIndex++)
12146             {
12147                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12148                 if (val != lastVal)
12149                 {
12150                     emitcode("mov", "a, #!constbyte", val);
12151                     lastVal = val;
12152                 }
12153
12154                 emitcode("movx", "@dptr, a");
12155                 emitcode("inc", "dptr");
12156             }
12157
12158             if (count > 1)
12159             {
12160                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12161             }
12162
12163             ix -= count;
12164         }
12165
12166         iLoop = iLoop->next;
12167     }
12168
12169     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12170 }
12171 #endif
12172
12173 /*-----------------------------------------------------------------*/
12174 /* genFarFarAssign - assignment when both are in far space         */
12175 /*-----------------------------------------------------------------*/
12176 static void
12177 genFarFarAssign (operand * result, operand * right, iCode * ic)
12178 {
12179   int size = AOP_SIZE (right);
12180   int offset = 0;
12181   symbol *rSym = NULL;
12182
12183   if (size == 1)
12184   {
12185       /* quick & easy case. */
12186       D (emitcode(";","genFarFarAssign (1 byte case)"));
12187       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12188       freeAsmop (right, NULL, ic, FALSE);
12189       /* now assign DPTR to result */
12190       _G.accInUse++;
12191       aopOp(result, ic, FALSE, FALSE);
12192       _G.accInUse--;
12193       aopPut (result, "a", 0);
12194       freeAsmop(result, NULL, ic, FALSE);
12195       return;
12196   }
12197
12198   /* See if we've got an underlying symbol to abuse. */
12199   if (IS_SYMOP(result) && OP_SYMBOL(result))
12200   {
12201       if (IS_TRUE_SYMOP(result))
12202       {
12203           rSym = OP_SYMBOL(result);
12204       }
12205       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12206       {
12207           rSym = OP_SYMBOL(result)->usl.spillLoc;
12208       }
12209   }
12210
12211   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12212   {
12213       /* We can use the '390 auto-toggle feature to good effect here. */
12214
12215       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12216       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12217       emitcode ("mov", "dptr,#%s", rSym->rname);
12218       /* DP2 = result, DP1 = right, DP1 is current. */
12219       while (size)
12220       {
12221           emitcode("movx", "a,@dptr");
12222           emitcode("movx", "@dptr,a");
12223           if (--size)
12224           {
12225                emitcode("inc", "dptr");
12226                emitcode("inc", "dptr");
12227           }
12228       }
12229       emitcode("mov", "dps,#0");
12230       freeAsmop (right, NULL, ic, FALSE);
12231 #if 0
12232 some alternative code for processors without auto-toggle
12233 no time to test now, so later well put in...kpb
12234         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12235         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12236         emitcode ("mov", "dptr,#%s", rSym->rname);
12237         /* DP2 = result, DP1 = right, DP1 is current. */
12238         while (size)
12239         {
12240           --size;
12241           emitcode("movx", "a,@dptr");
12242           if (size)
12243             emitcode("inc", "dptr");
12244           emitcode("inc", "dps");
12245           emitcode("movx", "@dptr,a");
12246           if (size)
12247             emitcode("inc", "dptr");
12248           emitcode("inc", "dps");
12249         }
12250         emitcode("mov", "dps,#0");
12251         freeAsmop (right, NULL, ic, FALSE);
12252 #endif
12253   }
12254   else
12255   {
12256       D (emitcode (";", "genFarFarAssign"));
12257       aopOp (result, ic, TRUE, TRUE);
12258
12259       _startLazyDPSEvaluation ();
12260
12261       while (size--)
12262         {
12263           aopPut (result,
12264                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12265           offset++;
12266         }
12267       _endLazyDPSEvaluation ();
12268       freeAsmop (result, NULL, ic, FALSE);
12269       freeAsmop (right, NULL, ic, FALSE);
12270   }
12271 }
12272
12273 /*-----------------------------------------------------------------*/
12274 /* genAssign - generate code for assignment                        */
12275 /*-----------------------------------------------------------------*/
12276 static void
12277 genAssign (iCode * ic)
12278 {
12279   operand *result, *right;
12280   int size, offset;
12281   unsigned long lit = 0L;
12282
12283   D (emitcode (";", "genAssign"));
12284
12285   result = IC_RESULT (ic);
12286   right = IC_RIGHT (ic);
12287
12288   /* if they are the same */
12289   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12290     return;
12291
12292   aopOp (right, ic, FALSE, FALSE);
12293
12294   emitcode (";", "genAssign: resultIsFar = %s",
12295             isOperandInFarSpace (result) ?
12296             "TRUE" : "FALSE");
12297
12298   /* special case both in far space */
12299   if ((AOP_TYPE (right) == AOP_DPTR ||
12300        AOP_TYPE (right) == AOP_DPTR2) &&
12301   /* IS_TRUE_SYMOP(result)       && */
12302       isOperandInFarSpace (result))
12303     {
12304       genFarFarAssign (result, right, ic);
12305       return;
12306     }
12307
12308   aopOp (result, ic, TRUE, FALSE);
12309
12310   /* if they are the same registers */
12311   if (sameRegs (AOP (right), AOP (result)))
12312     goto release;
12313
12314   /* if the result is a bit */
12315   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12316     {
12317       /* if the right size is a literal then
12318          we know what the value is */
12319       if (AOP_TYPE (right) == AOP_LIT)
12320         {
12321           if (((int) operandLitValue (right)))
12322             aopPut (result, one, 0);
12323           else
12324             aopPut (result, zero, 0);
12325           goto release;
12326         }
12327
12328       /* the right is also a bit variable */
12329       if (AOP_TYPE (right) == AOP_CRY)
12330         {
12331           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12332           aopPut (result, "c", 0);
12333           goto release;
12334         }
12335
12336       /* we need to or */
12337       toBoolean (right);
12338       aopPut (result, "a", 0);
12339       goto release;
12340     }
12341
12342   /* bit variables done */
12343   /* general case */
12344   size = getDataSize (result);
12345   offset = 0;
12346   if (AOP_TYPE (right) == AOP_LIT)
12347     lit = ulFromVal (AOP (right)->aopu.aop_lit);
12348
12349   if ((size > 1) &&
12350       (AOP_TYPE (result) != AOP_REG) &&
12351       (AOP_TYPE (right) == AOP_LIT) &&
12352       !IS_FLOAT (operandType (right)))
12353     {
12354       _startLazyDPSEvaluation ();
12355       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12356         {
12357           aopPut (result,
12358                   aopGet (right, offset, FALSE, FALSE, NULL),
12359                   offset);
12360           offset++;
12361           size--;
12362         }
12363       /* And now fill the rest with zeros. */
12364       if (size)
12365         {
12366           emitcode ("clr", "a");
12367         }
12368       while (size--)
12369         {
12370           aopPut (result, "a", offset++);
12371         }
12372       _endLazyDPSEvaluation ();
12373     }
12374   else
12375     {
12376       _startLazyDPSEvaluation ();
12377       while (size--)
12378         {
12379           aopPut (result,
12380                   aopGet (right, offset, FALSE, FALSE, NULL),
12381                   offset);
12382           offset++;
12383         }
12384       _endLazyDPSEvaluation ();
12385     }
12386   adjustArithmeticResult (ic);
12387
12388 release:
12389   freeAsmop (result, NULL, ic, TRUE);
12390   freeAsmop (right, NULL, ic, TRUE);
12391 }
12392
12393 /*-----------------------------------------------------------------*/
12394 /* genJumpTab - generates code for jump table                      */
12395 /*-----------------------------------------------------------------*/
12396 static void
12397 genJumpTab (iCode * ic)
12398 {
12399   symbol *jtab;
12400   char *l;
12401
12402   D (emitcode (";", "genJumpTab"));
12403
12404   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12405   /* get the condition into accumulator */
12406   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12407   MOVA (l);
12408   /* multiply by four! */
12409   emitcode ("add", "a,acc");
12410   emitcode ("add", "a,acc");
12411   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12412
12413   jtab = newiTempLabel (NULL);
12414   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12415   emitcode ("jmp", "@a+dptr");
12416   emitLabel (jtab);
12417   /* now generate the jump labels */
12418   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12419        jtab = setNextItem (IC_JTLABELS (ic)))
12420     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12421
12422 }
12423
12424 /*-----------------------------------------------------------------*/
12425 /* genCast - gen code for casting                                  */
12426 /*-----------------------------------------------------------------*/
12427 static void
12428 genCast (iCode * ic)
12429 {
12430   operand *result = IC_RESULT (ic);
12431   sym_link *ctype = operandType (IC_LEFT (ic));
12432   sym_link *rtype = operandType (IC_RIGHT (ic));
12433   operand *right = IC_RIGHT (ic);
12434   int size, offset;
12435
12436   D (emitcode (";", "genCast"));
12437
12438   /* if they are equivalent then do nothing */
12439   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12440     return;
12441
12442   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12443   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12444
12445   /* if the result is a bit (and not a bitfield) */
12446   if (IS_BIT (OP_SYMBOL (result)->type))
12447     {
12448       /* if the right size is a literal then
12449          we know what the value is */
12450       if (AOP_TYPE (right) == AOP_LIT)
12451         {
12452           if (((int) operandLitValue (right)))
12453             aopPut (result, one, 0);
12454           else
12455             aopPut (result, zero, 0);
12456
12457           goto release;
12458         }
12459
12460       /* the right is also a bit variable */
12461       if (AOP_TYPE (right) == AOP_CRY)
12462         {
12463           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12464           aopPut (result, "c", 0);
12465           goto release;
12466         }
12467
12468       /* we need to or */
12469       toBoolean (right);
12470       aopPut (result, "a", 0);
12471       goto release;
12472     }
12473
12474   /* if they are the same size : or less */
12475   if (AOP_SIZE (result) <= AOP_SIZE (right))
12476     {
12477
12478       /* if they are in the same place */
12479       if (sameRegs (AOP (right), AOP (result)))
12480         goto release;
12481
12482       /* if they in different places then copy */
12483       size = AOP_SIZE (result);
12484       offset = 0;
12485       _startLazyDPSEvaluation ();
12486       while (size--)
12487         {
12488           aopPut (result,
12489                   aopGet (right, offset, FALSE, FALSE, NULL),
12490                   offset);
12491           offset++;
12492         }
12493       _endLazyDPSEvaluation ();
12494       goto release;
12495     }
12496
12497   /* if the result is of type pointer */
12498   if (IS_PTR (ctype))
12499     {
12500
12501       int p_type;
12502       sym_link *type = operandType (right);
12503
12504       /* pointer to generic pointer */
12505       if (IS_GENPTR (ctype))
12506         {
12507           if (IS_PTR (type))
12508             {
12509               p_type = DCL_TYPE (type);
12510             }
12511           else
12512             {
12513 #if OLD_CAST_BEHAVIOR
12514               /* KV: we are converting a non-pointer type to
12515                * a generic pointer. This (ifdef'd out) code
12516                * says that the resulting generic pointer
12517                * should have the same class as the storage
12518                * location of the non-pointer variable.
12519                *
12520                * For example, converting an int (which happens
12521                * to be stored in DATA space) to a pointer results
12522                * in a DATA generic pointer; if the original int
12523                * in XDATA space, so will be the resulting pointer.
12524                *
12525                * I don't like that behavior, and thus this change:
12526                * all such conversions will be forced to XDATA and
12527                * throw a warning. If you want some non-XDATA
12528                * type, or you want to suppress the warning, you
12529                * must go through an intermediate cast, like so:
12530                *
12531                * char _generic *gp = (char _xdata *)(intVar);
12532                */
12533               sym_link *etype = getSpec (type);
12534
12535               /* we have to go by the storage class */
12536               if (SPEC_OCLS (etype) != generic)
12537                 {
12538                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12539                 }
12540               else
12541 #endif
12542                 {
12543                   /* Converting unknown class (i.e. register variable)
12544                    * to generic pointer. This is not good, but
12545                    * we'll make a guess (and throw a warning).
12546                    */
12547                   p_type = FPOINTER;
12548                   werror (W_INT_TO_GEN_PTR_CAST);
12549                 }
12550             }
12551
12552           /* the first two bytes are known */
12553           size = GPTRSIZE - 1;
12554           offset = 0;
12555           _startLazyDPSEvaluation ();
12556           while (size--)
12557             {
12558               aopPut (result,
12559                       aopGet (right, offset, FALSE, FALSE, NULL),
12560                       offset);
12561               offset++;
12562             }
12563           _endLazyDPSEvaluation ();
12564
12565           /* the last byte depending on type */
12566             {
12567                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12568                 char gpValStr[10];
12569
12570                 if (gpVal == -1)
12571                 {
12572                     // pointerTypeToGPByte will have bitched.
12573                     exit(1);
12574                 }
12575
12576                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12577                 aopPut (result, gpValStr, GPTRSIZE - 1);
12578             }
12579           goto release;
12580         }
12581
12582       /* just copy the pointers */
12583       size = AOP_SIZE (result);
12584       offset = 0;
12585       _startLazyDPSEvaluation ();
12586       while (size--)
12587         {
12588           aopPut (result,
12589                   aopGet (right, offset, FALSE, FALSE, NULL),
12590                   offset);
12591           offset++;
12592         }
12593       _endLazyDPSEvaluation ();
12594       goto release;
12595     }
12596
12597   /* so we now know that the size of destination is greater
12598      than the size of the source */
12599   /* we move to result for the size of source */
12600   size = AOP_SIZE (right);
12601   offset = 0;
12602   _startLazyDPSEvaluation ();
12603   while (size--)
12604     {
12605       aopPut (result,
12606               aopGet (right, offset, FALSE, FALSE, NULL),
12607               offset);
12608       offset++;
12609     }
12610   _endLazyDPSEvaluation ();
12611
12612   /* now depending on the sign of the source && destination */
12613   size = AOP_SIZE (result) - AOP_SIZE (right);
12614   /* if unsigned or not an integral type */
12615   /* also, if the source is a bit, we don't need to sign extend, because
12616    * it can't possibly have set the sign bit.
12617    */
12618   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12619     {
12620       while (size--)
12621         {
12622           aopPut (result, zero, offset++);
12623         }
12624     }
12625   else
12626     {
12627       /* we need to extend the sign :{ */
12628       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12629                         FALSE, FALSE, NULL));
12630       emitcode ("rlc", "a");
12631       emitcode ("subb", "a,acc");
12632       while (size--)
12633         aopPut (result, "a", offset++);
12634     }
12635
12636   /* we are done hurray !!!! */
12637
12638 release:
12639   freeAsmop (right, NULL, ic, TRUE);
12640   freeAsmop (result, NULL, ic, TRUE);
12641
12642 }
12643
12644 /*-----------------------------------------------------------------*/
12645 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12646 /*-----------------------------------------------------------------*/
12647 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12648 {
12649     operand *from , *to , *count;
12650     symbol *lbl;
12651     bitVect *rsave;
12652     int i;
12653
12654     /* we know it has to be 3 parameters */
12655     assert (nparms == 3);
12656
12657     rsave = newBitVect(16);
12658     /* save DPTR if it needs to be saved */
12659     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12660             if (bitVectBitValue(ic->rMask,i))
12661                     rsave = bitVectSetBit(rsave,i);
12662     }
12663     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12664                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12665     savermask(rsave);
12666
12667     to = parms[0];
12668     from = parms[1];
12669     count = parms[2];
12670
12671     aopOp (from, ic->next, FALSE, FALSE);
12672
12673     /* get from into DPTR1 */
12674     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12675     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12676     if (options.model == MODEL_FLAT24) {
12677         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12678     }
12679
12680     freeAsmop (from, NULL, ic, FALSE);
12681     aopOp (to, ic, FALSE, FALSE);
12682     /* get "to" into DPTR */
12683     /* if the operand is already in dptr
12684        then we do nothing else we move the value to dptr */
12685     if (AOP_TYPE (to) != AOP_STR) {
12686         /* if already in DPTR then we need to push */
12687         if (AOP_TYPE(to) == AOP_DPTR) {
12688             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12689             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12690             if (options.model == MODEL_FLAT24)
12691                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12692             emitcode ("pop", "dph");
12693             emitcode ("pop", "dpl");
12694         } else {
12695             _startLazyDPSEvaluation ();
12696             /* if this is remateriazable */
12697             if (AOP_TYPE (to) == AOP_IMMD) {
12698                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12699             } else {                    /* we need to get it byte by byte */
12700                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12701                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12702                 if (options.model == MODEL_FLAT24) {
12703                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12704                 }
12705             }
12706             _endLazyDPSEvaluation ();
12707         }
12708     }
12709     freeAsmop (to, NULL, ic, FALSE);
12710     _G.dptrInUse = _G.dptr1InUse = 1;
12711     aopOp (count, ic->next->next, FALSE,FALSE);
12712     lbl =newiTempLabel(NULL);
12713
12714     /* now for the actual copy */
12715     if (AOP_TYPE(count) == AOP_LIT &&
12716         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12717         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12718         if (fromc) {
12719             emitcode ("lcall","__bi_memcpyc2x_s");
12720         } else {
12721             emitcode ("lcall","__bi_memcpyx2x_s");
12722         }
12723         freeAsmop (count, NULL, ic, FALSE);
12724     } else {
12725         symbol *lbl1 = newiTempLabel(NULL);
12726
12727         emitcode (";"," Auto increment but no djnz");
12728         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12729         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12730         freeAsmop (count, NULL, ic, FALSE);
12731         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12732         emitLabel (lbl);
12733         if (fromc) {
12734             emitcode ("clr","a");
12735             emitcode ("movc", "a,@a+dptr");
12736         } else
12737             emitcode ("movx", "a,@dptr");
12738         emitcode ("movx", "@dptr,a");
12739         emitcode ("inc", "dptr");
12740         emitcode ("inc", "dptr");
12741         emitcode ("mov","a,b");
12742         emitcode ("orl","a,_ap");
12743         emitcode ("jz","!tlabel",lbl1->key+100);
12744         emitcode ("mov","a,_ap");
12745         emitcode ("add","a,#!constbyte",0xFF);
12746         emitcode ("mov","_ap,a");
12747         emitcode ("mov","a,b");
12748         emitcode ("addc","a,#!constbyte",0xFF);
12749         emitcode ("mov","b,a");
12750         emitcode ("sjmp","!tlabel",lbl->key+100);
12751         emitLabel (lbl1);
12752     }
12753     emitcode ("mov", "dps,#0");
12754     _G.dptrInUse = _G.dptr1InUse = 0;
12755     unsavermask(rsave);
12756
12757 }
12758
12759 /*-----------------------------------------------------------------*/
12760 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12761 /*-----------------------------------------------------------------*/
12762 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12763 {
12764     operand *from , *to , *count;
12765     symbol *lbl,*lbl2;
12766     bitVect *rsave;
12767     int i;
12768
12769     /* we know it has to be 3 parameters */
12770     assert (nparms == 3);
12771
12772     rsave = newBitVect(16);
12773     /* save DPTR if it needs to be saved */
12774     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12775             if (bitVectBitValue(ic->rMask,i))
12776                     rsave = bitVectSetBit(rsave,i);
12777     }
12778     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12779                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12780     savermask(rsave);
12781
12782     to = parms[0];
12783     from = parms[1];
12784     count = parms[2];
12785
12786     aopOp (from, ic->next, FALSE, FALSE);
12787
12788     /* get from into DPTR1 */
12789     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12790     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12791     if (options.model == MODEL_FLAT24) {
12792         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12793     }
12794
12795     freeAsmop (from, NULL, ic, FALSE);
12796     aopOp (to, ic, FALSE, FALSE);
12797     /* get "to" into DPTR */
12798     /* if the operand is already in dptr
12799        then we do nothing else we move the value to dptr */
12800     if (AOP_TYPE (to) != AOP_STR) {
12801         /* if already in DPTR then we need to push */
12802         if (AOP_TYPE(to) == AOP_DPTR) {
12803             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12804             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12805             if (options.model == MODEL_FLAT24)
12806                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12807             emitcode ("pop", "dph");
12808             emitcode ("pop", "dpl");
12809         } else {
12810             _startLazyDPSEvaluation ();
12811             /* if this is remateriazable */
12812             if (AOP_TYPE (to) == AOP_IMMD) {
12813                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12814             } else {                    /* we need to get it byte by byte */
12815                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12816                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12817                 if (options.model == MODEL_FLAT24) {
12818                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12819                 }
12820             }
12821             _endLazyDPSEvaluation ();
12822         }
12823     }
12824     freeAsmop (to, NULL, ic, FALSE);
12825     _G.dptrInUse = _G.dptr1InUse = 1;
12826     aopOp (count, ic->next->next, FALSE,FALSE);
12827     lbl =newiTempLabel(NULL);
12828     lbl2 =newiTempLabel(NULL);
12829
12830     /* now for the actual compare */
12831     if (AOP_TYPE(count) == AOP_LIT &&
12832         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12833         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12834         if (fromc)
12835             emitcode("lcall","__bi_memcmpc2x_s");
12836         else
12837             emitcode("lcall","__bi_memcmpx2x_s");
12838         freeAsmop (count, NULL, ic, FALSE);
12839         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12840         aopPut(IC_RESULT(ic),"a",0);
12841         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12842     } else {
12843         symbol *lbl1 = newiTempLabel(NULL);
12844
12845         emitcode("push","ar0");
12846         emitcode (";"," Auto increment but no djnz");
12847         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12848         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12849         freeAsmop (count, NULL, ic, FALSE);
12850         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12851         emitLabel (lbl);
12852         if (fromc) {
12853             emitcode ("clr","a");
12854             emitcode ("movc", "a,@a+dptr");
12855         } else
12856             emitcode ("movx", "a,@dptr");
12857         emitcode ("mov","r0,a");
12858         emitcode ("movx", "a,@dptr");
12859         emitcode ("clr","c");
12860         emitcode ("subb","a,r0");
12861         emitcode ("jnz","!tlabel",lbl2->key+100);
12862         emitcode ("inc", "dptr");
12863         emitcode ("inc", "dptr");
12864         emitcode ("mov","a,b");
12865         emitcode ("orl","a,_ap");
12866         emitcode ("jz","!tlabel",lbl1->key+100);
12867         emitcode ("mov","a,_ap");
12868         emitcode ("add","a,#!constbyte",0xFF);
12869         emitcode ("mov","_ap,a");
12870         emitcode ("mov","a,b");
12871         emitcode ("addc","a,#!constbyte",0xFF);
12872         emitcode ("mov","b,a");
12873         emitcode ("sjmp","!tlabel",lbl->key+100);
12874         emitLabel (lbl1);
12875         emitcode ("clr","a");
12876         emitLabel (lbl2);
12877         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12878         aopPut(IC_RESULT(ic),"a",0);
12879         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12880         emitcode("pop","ar0");
12881         emitcode ("mov", "dps,#0");
12882     }
12883     _G.dptrInUse = _G.dptr1InUse = 0;
12884     unsavermask(rsave);
12885
12886 }
12887
12888 /*-----------------------------------------------------------------*/
12889 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12890 /* port, first parameter output area second parameter pointer to   */
12891 /* port third parameter count                                      */
12892 /*-----------------------------------------------------------------*/
12893 static void genInp( iCode *ic, int nparms, operand **parms)
12894 {
12895     operand *from , *to , *count;
12896     symbol *lbl;
12897     bitVect *rsave;
12898     int i;
12899
12900     /* we know it has to be 3 parameters */
12901     assert (nparms == 3);
12902
12903     rsave = newBitVect(16);
12904     /* save DPTR if it needs to be saved */
12905     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12906             if (bitVectBitValue(ic->rMask,i))
12907                     rsave = bitVectSetBit(rsave,i);
12908     }
12909     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12910                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12911     savermask(rsave);
12912
12913     to = parms[0];
12914     from = parms[1];
12915     count = parms[2];
12916
12917     aopOp (from, ic->next, FALSE, FALSE);
12918
12919     /* get from into DPTR1 */
12920     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12921     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12922     if (options.model == MODEL_FLAT24) {
12923         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12924     }
12925
12926     freeAsmop (from, NULL, ic, FALSE);
12927     aopOp (to, ic, FALSE, FALSE);
12928     /* get "to" into DPTR */
12929     /* if the operand is already in dptr
12930        then we do nothing else we move the value to dptr */
12931     if (AOP_TYPE (to) != AOP_STR) {
12932         /* if already in DPTR then we need to push */
12933         if (AOP_TYPE(to) == AOP_DPTR) {
12934             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12935             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12936             if (options.model == MODEL_FLAT24)
12937                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12938             emitcode ("pop", "dph");
12939             emitcode ("pop", "dpl");
12940         } else {
12941             _startLazyDPSEvaluation ();
12942             /* if this is remateriazable */
12943             if (AOP_TYPE (to) == AOP_IMMD) {
12944                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12945             } else {                    /* we need to get it byte by byte */
12946                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12947                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12948                 if (options.model == MODEL_FLAT24) {
12949                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12950                 }
12951             }
12952             _endLazyDPSEvaluation ();
12953         }
12954     }
12955     freeAsmop (to, NULL, ic, FALSE);
12956
12957     _G.dptrInUse = _G.dptr1InUse = 1;
12958     aopOp (count, ic->next->next, FALSE,FALSE);
12959     lbl =newiTempLabel(NULL);
12960
12961     /* now for the actual copy */
12962     if (AOP_TYPE(count) == AOP_LIT &&
12963         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12964         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12965         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12966         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12967         freeAsmop (count, NULL, ic, FALSE);
12968         emitLabel (lbl);
12969         emitcode ("movx", "a,@dptr");   /* read data from port */
12970         emitcode ("dec","dps");         /* switch to DPTR */
12971         emitcode ("movx", "@dptr,a");   /* save into location */
12972         emitcode ("inc", "dptr");       /* point to next area */
12973         emitcode ("inc","dps");         /* switch to DPTR2 */
12974         emitcode ("djnz","b,!tlabel",lbl->key+100);
12975     } else {
12976         symbol *lbl1 = newiTempLabel(NULL);
12977
12978         emitcode (";"," Auto increment but no djnz");
12979         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12980         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12981         freeAsmop (count, NULL, ic, FALSE);
12982         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12983         emitLabel (lbl);
12984         emitcode ("movx", "a,@dptr");
12985         emitcode ("dec","dps");         /* switch to DPTR */
12986         emitcode ("movx", "@dptr,a");
12987         emitcode ("inc", "dptr");
12988         emitcode ("inc","dps");         /* switch to DPTR2 */
12989 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12990 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12991         emitcode ("mov","a,b");
12992         emitcode ("orl","a,_ap");
12993         emitcode ("jz","!tlabel",lbl1->key+100);
12994         emitcode ("mov","a,_ap");
12995         emitcode ("add","a,#!constbyte",0xFF);
12996         emitcode ("mov","_ap,a");
12997         emitcode ("mov","a,b");
12998         emitcode ("addc","a,#!constbyte",0xFF);
12999         emitcode ("mov","b,a");
13000         emitcode ("sjmp","!tlabel",lbl->key+100);
13001         emitLabel (lbl1);
13002     }
13003     emitcode ("mov", "dps,#0");
13004     _G.dptrInUse = _G.dptr1InUse = 0;
13005     unsavermask(rsave);
13006
13007 }
13008
13009 /*-----------------------------------------------------------------*/
13010 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
13011 /* port, first parameter output area second parameter pointer to   */
13012 /* port third parameter count                                      */
13013 /*-----------------------------------------------------------------*/
13014 static void genOutp( iCode *ic, int nparms, operand **parms)
13015 {
13016     operand *from , *to , *count;
13017     symbol *lbl;
13018     bitVect *rsave;
13019     int i;
13020
13021     /* we know it has to be 3 parameters */
13022     assert (nparms == 3);
13023
13024     rsave = newBitVect(16);
13025     /* save DPTR if it needs to be saved */
13026     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13027             if (bitVectBitValue(ic->rMask,i))
13028                     rsave = bitVectSetBit(rsave,i);
13029     }
13030     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13031                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13032     savermask(rsave);
13033
13034     to = parms[0];
13035     from = parms[1];
13036     count = parms[2];
13037
13038     aopOp (from, ic->next, FALSE, FALSE);
13039
13040     /* get from into DPTR1 */
13041     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
13042     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
13043     if (options.model == MODEL_FLAT24) {
13044         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
13045     }
13046
13047     freeAsmop (from, NULL, ic, FALSE);
13048     aopOp (to, ic, FALSE, FALSE);
13049     /* get "to" into DPTR */
13050     /* if the operand is already in dptr
13051        then we do nothing else we move the value to dptr */
13052     if (AOP_TYPE (to) != AOP_STR) {
13053         /* if already in DPTR then we need to push */
13054         if (AOP_TYPE(to) == AOP_DPTR) {
13055             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13056             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13057             if (options.model == MODEL_FLAT24)
13058                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13059             emitcode ("pop", "dph");
13060             emitcode ("pop", "dpl");
13061         } else {
13062             _startLazyDPSEvaluation ();
13063             /* if this is remateriazable */
13064             if (AOP_TYPE (to) == AOP_IMMD) {
13065                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13066             } else {                    /* we need to get it byte by byte */
13067                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13068                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13069                 if (options.model == MODEL_FLAT24) {
13070                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13071                 }
13072             }
13073             _endLazyDPSEvaluation ();
13074         }
13075     }
13076     freeAsmop (to, NULL, ic, FALSE);
13077
13078     _G.dptrInUse = _G.dptr1InUse = 1;
13079     aopOp (count, ic->next->next, FALSE,FALSE);
13080     lbl =newiTempLabel(NULL);
13081
13082     /* now for the actual copy */
13083     if (AOP_TYPE(count) == AOP_LIT &&
13084         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13085         emitcode (";","OH  JOY auto increment with djnz (very fast)");
13086         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13087         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13088         emitLabel (lbl);
13089         emitcode ("movx", "a,@dptr");   /* read data from port */
13090         emitcode ("inc","dps");         /* switch to DPTR2 */
13091         emitcode ("movx", "@dptr,a");   /* save into location */
13092         emitcode ("inc", "dptr");       /* point to next area */
13093         emitcode ("dec","dps");         /* switch to DPTR */
13094         emitcode ("djnz","b,!tlabel",lbl->key+100);
13095         freeAsmop (count, NULL, ic, FALSE);
13096     } else {
13097         symbol *lbl1 = newiTempLabel(NULL);
13098
13099         emitcode (";"," Auto increment but no djnz");
13100         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13101         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13102         freeAsmop (count, NULL, ic, FALSE);
13103         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13104         emitLabel (lbl);
13105         emitcode ("movx", "a,@dptr");
13106         emitcode ("inc", "dptr");
13107         emitcode ("inc","dps");         /* switch to DPTR2 */
13108         emitcode ("movx", "@dptr,a");
13109         emitcode ("dec","dps");         /* switch to DPTR */
13110         emitcode ("mov","a,b");
13111         emitcode ("orl","a,_ap");
13112         emitcode ("jz","!tlabel",lbl1->key+100);
13113         emitcode ("mov","a,_ap");
13114         emitcode ("add","a,#!constbyte",0xFF);
13115         emitcode ("mov","_ap,a");
13116         emitcode ("mov","a,b");
13117         emitcode ("addc","a,#!constbyte",0xFF);
13118         emitcode ("mov","b,a");
13119         emitcode ("sjmp","!tlabel",lbl->key+100);
13120         emitLabel (lbl1);
13121     }
13122     emitcode ("mov", "dps,#0");
13123     _G.dptrInUse = _G.dptr1InUse = 0;
13124     unsavermask(rsave);
13125
13126 }
13127
13128 /*-----------------------------------------------------------------*/
13129 /* genSwapW - swap lower & high order bytes                        */
13130 /*-----------------------------------------------------------------*/
13131 static void genSwapW(iCode *ic, int nparms, operand **parms)
13132 {
13133     operand *dest;
13134     operand *src;
13135     assert (nparms==1);
13136
13137     src = parms[0];
13138     dest=IC_RESULT(ic);
13139
13140     assert(getSize(operandType(src))==2);
13141
13142     aopOp (src, ic, FALSE, FALSE);
13143     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13144     _G.accInUse++;
13145     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13146     _G.accInUse--;
13147     freeAsmop (src, NULL, ic, FALSE);
13148
13149     aopOp (dest,ic, FALSE, FALSE);
13150     aopPut(dest,"b",0);
13151     aopPut(dest,"a",1);
13152     freeAsmop (dest, NULL, ic, FALSE);
13153 }
13154
13155 /*-----------------------------------------------------------------*/
13156 /* genMemsetX - gencode for memSetX data                           */
13157 /*-----------------------------------------------------------------*/
13158 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13159 {
13160     operand *to , *val , *count;
13161     symbol *lbl;
13162     char *l;
13163     int i;
13164     bitVect *rsave;
13165
13166     /* we know it has to be 3 parameters */
13167     assert (nparms == 3);
13168
13169     to = parms[0];
13170     val = parms[1];
13171     count = parms[2];
13172
13173     /* save DPTR if it needs to be saved */
13174     rsave = newBitVect(16);
13175     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13176             if (bitVectBitValue(ic->rMask,i))
13177                     rsave = bitVectSetBit(rsave,i);
13178     }
13179     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13180                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13181     savermask(rsave);
13182
13183     aopOp (to, ic, FALSE, FALSE);
13184     /* get "to" into DPTR */
13185     /* if the operand is already in dptr
13186        then we do nothing else we move the value to dptr */
13187     if (AOP_TYPE (to) != AOP_STR) {
13188         /* if already in DPTR then we need to push */
13189         if (AOP_TYPE(to) == AOP_DPTR) {
13190             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13191             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13192             if (options.model == MODEL_FLAT24)
13193                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13194             emitcode ("pop", "dph");
13195             emitcode ("pop", "dpl");
13196         } else {
13197             _startLazyDPSEvaluation ();
13198             /* if this is remateriazable */
13199             if (AOP_TYPE (to) == AOP_IMMD) {
13200                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13201             } else {                    /* we need to get it byte by byte */
13202                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13203                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13204                 if (options.model == MODEL_FLAT24) {
13205                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13206                 }
13207             }
13208             _endLazyDPSEvaluation ();
13209         }
13210     }
13211     freeAsmop (to, NULL, ic, FALSE);
13212
13213     aopOp (val, ic->next->next, FALSE,FALSE);
13214     aopOp (count, ic->next->next, FALSE,FALSE);
13215     lbl =newiTempLabel(NULL);
13216     /* now for the actual copy */
13217     if (AOP_TYPE(count) == AOP_LIT &&
13218         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13219         l = aopGet(val, 0, FALSE, FALSE, NULL);
13220         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13221         MOVA(l);
13222         emitLabel (lbl);
13223         emitcode ("movx", "@dptr,a");
13224         emitcode ("inc", "dptr");
13225         emitcode ("djnz","b,!tlabel",lbl->key+100);
13226     } else {
13227         symbol *lbl1 = newiTempLabel(NULL);
13228
13229         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13230         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13231         emitLabel (lbl);
13232         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13233         emitcode ("movx", "@dptr,a");
13234         emitcode ("inc", "dptr");
13235         emitcode ("mov","a,b");
13236         emitcode ("orl","a,_ap");
13237         emitcode ("jz","!tlabel",lbl1->key+100);
13238         emitcode ("mov","a,_ap");
13239         emitcode ("add","a,#!constbyte",0xFF);
13240         emitcode ("mov","_ap,a");
13241         emitcode ("mov","a,b");
13242         emitcode ("addc","a,#!constbyte",0xFF);
13243         emitcode ("mov","b,a");
13244         emitcode ("sjmp","!tlabel",lbl->key+100);
13245         emitLabel (lbl1);
13246     }
13247     freeAsmop (count, NULL, ic, FALSE);
13248     unsavermask(rsave);
13249 }
13250
13251 /*-----------------------------------------------------------------*/
13252 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13253 /*-----------------------------------------------------------------*/
13254 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13255 {
13256         bitVect *rsave ;
13257         operand *pnum, *result;
13258         int i;
13259
13260         assert (nparms==1);
13261         /* save registers that need to be saved */
13262         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13263                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13264
13265         pnum = parms[0];
13266         aopOp (pnum, ic, FALSE, FALSE);
13267         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13268         freeAsmop (pnum, NULL, ic, FALSE);
13269         emitcode ("lcall","NatLib_LoadPrimitive");
13270         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13271         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13272             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13273                 for (i = (size-1) ; i >= 0 ; i-- ) {
13274                         emitcode ("push","a%s",javaRet[i]);
13275                 }
13276                 for (i=0; i < size ; i++ ) {
13277                         emitcode ("pop","a%s",
13278                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13279                 }
13280         } else {
13281                 for (i = 0 ; i < size ; i++ ) {
13282                         aopPut(result,javaRet[i],i);
13283                 }
13284         }
13285         freeAsmop (result, NULL, ic, FALSE);
13286         unsavermask(rsave);
13287 }
13288
13289 /*-----------------------------------------------------------------*/
13290 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13291 /*-----------------------------------------------------------------*/
13292 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13293 {
13294         bitVect *rsave ;
13295         operand *pnum, *result;
13296         int size = 3;
13297         int i;
13298
13299         assert (nparms==1);
13300         /* save registers that need to be saved */
13301         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13302                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13303
13304         pnum = parms[0];
13305         aopOp (pnum, ic, FALSE, FALSE);
13306         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13307         freeAsmop (pnum, NULL, ic, FALSE);
13308         emitcode ("lcall","NatLib_LoadPointer");
13309         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13310         if (AOP_TYPE(result)!=AOP_STR) {
13311                 for (i = 0 ; i < size ; i++ ) {
13312                         aopPut(result,fReturn[i],i);
13313                 }
13314         }
13315         freeAsmop (result, NULL, ic, FALSE);
13316         unsavermask(rsave);
13317 }
13318
13319 /*-----------------------------------------------------------------*/
13320 /* genNatLibInstallStateBlock -                                    */
13321 /*-----------------------------------------------------------------*/
13322 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13323                                        operand **parms, const char *name)
13324 {
13325         bitVect *rsave ;
13326         operand *psb, *handle;
13327         assert (nparms==2);
13328
13329         /* save registers that need to be saved */
13330         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13331                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13332         psb = parms[0];
13333         handle = parms[1];
13334
13335         /* put pointer to state block into DPTR1 */
13336         aopOp (psb, ic, FALSE, FALSE);
13337         if (AOP_TYPE (psb) == AOP_IMMD) {
13338                 emitcode ("mov","dps,#1");
13339                 emitcode ("mov", "dptr,%s",
13340                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13341                 emitcode ("mov","dps,#0");
13342         } else {
13343                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13344                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13345                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13346         }
13347         freeAsmop (psb, NULL, ic, FALSE);
13348
13349         /* put libraryID into DPTR */
13350         emitcode ("mov","dptr,#LibraryID");
13351
13352         /* put handle into r3:r2 */
13353         aopOp (handle, ic, FALSE, FALSE);
13354         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13355                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13356                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13357                 emitcode ("pop","ar3");
13358                 emitcode ("pop","ar2");
13359         } else {
13360                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13361                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13362         }
13363         freeAsmop (psb, NULL, ic, FALSE);
13364
13365         /* make the call */
13366         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13367
13368         /* put return value into place*/
13369         _G.accInUse++;
13370         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13371         _G.accInUse--;
13372         aopPut(IC_RESULT(ic),"a",0);
13373         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13374         unsavermask(rsave);
13375 }
13376
13377 /*-----------------------------------------------------------------*/
13378 /* genNatLibRemoveStateBlock -                                     */
13379 /*-----------------------------------------------------------------*/
13380 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13381 {
13382         bitVect *rsave ;
13383
13384         assert(nparms==0);
13385
13386         /* save registers that need to be saved */
13387         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13388                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13389
13390         /* put libraryID into DPTR */
13391         emitcode ("mov","dptr,#LibraryID");
13392         /* make the call */
13393         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13394         unsavermask(rsave);
13395 }
13396
13397 /*-----------------------------------------------------------------*/
13398 /* genNatLibGetStateBlock -                                        */
13399 /*-----------------------------------------------------------------*/
13400 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13401                                    operand **parms,const char *name)
13402 {
13403         bitVect *rsave ;
13404         symbol *lbl = newiTempLabel(NULL);
13405
13406         assert(nparms==0);
13407         /* save registers that need to be saved */
13408         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13409                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13410
13411         /* put libraryID into DPTR */
13412         emitcode ("mov","dptr,#LibraryID");
13413         /* make the call */
13414         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13415         emitcode ("jnz","!tlabel",lbl->key+100);
13416
13417         /* put return value into place */
13418         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13419         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13420                 emitcode ("push","ar3");
13421                 emitcode ("push","ar2");
13422                 emitcode ("pop","%s",
13423                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13424                 emitcode ("pop","%s",
13425                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13426         } else {
13427                 aopPut(IC_RESULT(ic),"r2",0);
13428                 aopPut(IC_RESULT(ic),"r3",1);
13429         }
13430         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13431         emitLabel (lbl);
13432         unsavermask(rsave);
13433 }
13434
13435 /*-----------------------------------------------------------------*/
13436 /* genMMMalloc -                                                   */
13437 /*-----------------------------------------------------------------*/
13438 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13439                          int size, const char *name)
13440 {
13441         bitVect *rsave ;
13442         operand *bsize;
13443         symbol *rsym;
13444         symbol *lbl = newiTempLabel(NULL);
13445
13446         assert (nparms == 1);
13447         /* save registers that need to be saved */
13448         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13449                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13450
13451         bsize=parms[0];
13452         aopOp (bsize,ic,FALSE,FALSE);
13453
13454         /* put the size in R4-R2 */
13455         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13456                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13457                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13458                 if (size==3) {
13459                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13460                         emitcode("pop","ar4");
13461                 }
13462                 emitcode("pop","ar3");
13463                 emitcode("pop","ar2");
13464         } else {
13465                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13466                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13467                 if (size==3) {
13468                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13469                 }
13470         }
13471         freeAsmop (bsize, NULL, ic, FALSE);
13472
13473         /* make the call */
13474         emitcode ("lcall","MM_%s",name);
13475         emitcode ("jz","!tlabel",lbl->key+100);
13476         emitcode ("mov","r2,#!constbyte",0xff);
13477         emitcode ("mov","r3,#!constbyte",0xff);
13478         emitLabel (lbl);
13479         /* we don't care about the pointer : we just save the handle */
13480         rsym = OP_SYMBOL(IC_RESULT(ic));
13481         if (rsym->liveFrom != rsym->liveTo) {
13482                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13483                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13484                         emitcode ("push","ar3");
13485                         emitcode ("push","ar2");
13486                         emitcode ("pop","%s",
13487                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13488                         emitcode ("pop","%s",
13489                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13490                 } else {
13491                         aopPut(IC_RESULT(ic),"r2",0);
13492                         aopPut(IC_RESULT(ic),"r3",1);
13493                 }
13494                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13495         }
13496         unsavermask(rsave);
13497 }
13498
13499 /*-----------------------------------------------------------------*/
13500 /* genMMDeref -                                                    */
13501 /*-----------------------------------------------------------------*/
13502 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13503 {
13504         bitVect *rsave ;
13505         operand *handle;
13506
13507         assert (nparms == 1);
13508         /* save registers that need to be saved */
13509         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13510                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13511
13512         handle=parms[0];
13513         aopOp (handle,ic,FALSE,FALSE);
13514
13515         /* put the size in R4-R2 */
13516         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13517                 emitcode("push","%s",
13518                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13519                 emitcode("push","%s",
13520                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13521                 emitcode("pop","ar3");
13522                 emitcode("pop","ar2");
13523         } else {
13524                 emitcode ("mov","r2,%s",
13525                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13526                 emitcode ("mov","r3,%s",
13527                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13528         }
13529         freeAsmop (handle, NULL, ic, FALSE);
13530
13531         /* make the call */
13532         emitcode ("lcall","MM_Deref");
13533
13534         {
13535                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13536                 if (rsym->liveFrom != rsym->liveTo) {
13537                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13538                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13539                             _startLazyDPSEvaluation ();
13540
13541                             aopPut(IC_RESULT(ic),"dpl",0);
13542                             aopPut(IC_RESULT(ic),"dph",1);
13543                             aopPut(IC_RESULT(ic),"dpx",2);
13544
13545                             _endLazyDPSEvaluation ();
13546
13547                         }
13548                 }
13549         }
13550         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13551         unsavermask(rsave);
13552 }
13553
13554 /*-----------------------------------------------------------------*/
13555 /* genMMUnrestrictedPersist -                                      */
13556 /*-----------------------------------------------------------------*/
13557 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13558 {
13559         bitVect *rsave ;
13560         operand *handle;
13561
13562         assert (nparms == 1);
13563         /* save registers that need to be saved */
13564         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13565                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13566
13567         handle=parms[0];
13568         aopOp (handle,ic,FALSE,FALSE);
13569
13570         /* put the size in R3-R2 */
13571         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13572                 emitcode("push","%s",
13573                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13574                 emitcode("push","%s",
13575                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13576                 emitcode("pop","ar3");
13577                 emitcode("pop","ar2");
13578         } else {
13579                 emitcode ("mov","r2,%s",
13580                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13581                 emitcode ("mov","r3,%s",
13582                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13583         }
13584         freeAsmop (handle, NULL, ic, FALSE);
13585
13586         /* make the call */
13587         emitcode ("lcall","MM_UnrestrictedPersist");
13588
13589         {
13590                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13591                 if (rsym->liveFrom != rsym->liveTo) {
13592                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13593                         aopPut(IC_RESULT(ic),"a",0);
13594                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13595                 }
13596         }
13597         unsavermask(rsave);
13598 }
13599
13600 /*-----------------------------------------------------------------*/
13601 /* genSystemExecJavaProcess -                                      */
13602 /*-----------------------------------------------------------------*/
13603 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13604 {
13605         bitVect *rsave ;
13606         operand *handle, *pp;
13607
13608         assert (nparms==2);
13609         /* save registers that need to be saved */
13610         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13611                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13612
13613         pp = parms[0];
13614         handle = parms[1];
13615
13616         /* put the handle in R3-R2 */
13617         aopOp (handle,ic,FALSE,FALSE);
13618         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13619                 emitcode("push","%s",
13620                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13621                 emitcode("push","%s",
13622                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13623                 emitcode("pop","ar3");
13624                 emitcode("pop","ar2");
13625         } else {
13626                 emitcode ("mov","r2,%s",
13627                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13628                 emitcode ("mov","r3,%s",
13629                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13630         }
13631         freeAsmop (handle, NULL, ic, FALSE);
13632
13633         /* put pointer in DPTR */
13634         aopOp (pp,ic,FALSE,FALSE);
13635         if (AOP_TYPE(pp) == AOP_IMMD) {
13636                 emitcode ("mov", "dptr,%s",
13637                           aopGet (pp, 0, TRUE, FALSE, NULL));
13638         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13639                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13640                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13641                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13642         }
13643         freeAsmop (handle, NULL, ic, FALSE);
13644
13645         /* make the call */
13646         emitcode ("lcall","System_ExecJavaProcess");
13647
13648         /* put result in place */
13649         {
13650                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13651                 if (rsym->liveFrom != rsym->liveTo) {
13652                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13653                         aopPut(IC_RESULT(ic),"a",0);
13654                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13655                 }
13656         }
13657
13658         unsavermask(rsave);
13659 }
13660
13661 /*-----------------------------------------------------------------*/
13662 /* genSystemRTCRegisters -                                         */
13663 /*-----------------------------------------------------------------*/
13664 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13665                                   char *name)
13666 {
13667         bitVect *rsave ;
13668         operand *pp;
13669
13670         assert (nparms==1);
13671         /* save registers that need to be saved */
13672         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13673                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13674
13675         pp=parms[0];
13676         /* put pointer in DPTR */
13677         aopOp (pp,ic,FALSE,FALSE);
13678         if (AOP_TYPE (pp) == AOP_IMMD) {
13679                 emitcode ("mov","dps,#1");
13680                 emitcode ("mov", "dptr,%s",
13681                           aopGet (pp, 0, TRUE, FALSE, NULL));
13682                 emitcode ("mov","dps,#0");
13683         } else {
13684                 emitcode ("mov","dpl1,%s",
13685                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13686                 emitcode ("mov","dph1,%s",
13687                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13688                 emitcode ("mov","dpx1,%s",
13689                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13690         }
13691         freeAsmop (pp, NULL, ic, FALSE);
13692
13693         /* make the call */
13694         emitcode ("lcall","System_%sRTCRegisters",name);
13695
13696         unsavermask(rsave);
13697 }
13698
13699 /*-----------------------------------------------------------------*/
13700 /* genSystemThreadSleep -                                          */
13701 /*-----------------------------------------------------------------*/
13702 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13703 {
13704         bitVect *rsave ;
13705         operand *to, *s;
13706
13707         assert (nparms==1);
13708         /* save registers that need to be saved */
13709         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13710                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13711
13712         to = parms[0];
13713         aopOp(to,ic,FALSE,FALSE);
13714         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13715             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13716                 emitcode ("push","%s",
13717                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13718                 emitcode ("push","%s",
13719                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13720                 emitcode ("push","%s",
13721                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13722                 emitcode ("push","%s",
13723                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13724                 emitcode ("pop","ar3");
13725                 emitcode ("pop","ar2");
13726                 emitcode ("pop","ar1");
13727                 emitcode ("pop","ar0");
13728         } else {
13729                 emitcode ("mov","r0,%s",
13730                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13731                 emitcode ("mov","r1,%s",
13732                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13733                 emitcode ("mov","r2,%s",
13734                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13735                 emitcode ("mov","r3,%s",
13736                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13737         }
13738         freeAsmop (to, NULL, ic, FALSE);
13739
13740         /* suspend in acc */
13741         s = parms[1];
13742         aopOp(s,ic,FALSE,FALSE);
13743         emitcode ("mov","a,%s",
13744                   aopGet(s,0,FALSE,TRUE,NULL));
13745         freeAsmop (s, NULL, ic, FALSE);
13746
13747         /* make the call */
13748         emitcode ("lcall","System_%s",name);
13749
13750         unsavermask(rsave);
13751 }
13752
13753 /*-----------------------------------------------------------------*/
13754 /* genSystemThreadResume -                                         */
13755 /*-----------------------------------------------------------------*/
13756 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13757 {
13758         bitVect *rsave ;
13759         operand *tid,*pid;
13760
13761         assert (nparms==2);
13762         /* save registers that need to be saved */
13763         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13764                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13765
13766         tid = parms[0];
13767         pid = parms[1];
13768
13769         /* PID in R0 */
13770         aopOp(pid,ic,FALSE,FALSE);
13771         emitcode ("mov","r0,%s",
13772                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13773         freeAsmop (pid, NULL, ic, FALSE);
13774
13775         /* tid into ACC */
13776         aopOp(tid,ic,FALSE,FALSE);
13777         emitcode ("mov","a,%s",
13778                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13779         freeAsmop (tid, NULL, ic, FALSE);
13780
13781         emitcode ("lcall","System_ThreadResume");
13782
13783         /* put result into place */
13784         {
13785                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13786                 if (rsym->liveFrom != rsym->liveTo) {
13787                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13788                         aopPut(IC_RESULT(ic),"a",0);
13789                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13790                 }
13791         }
13792         unsavermask(rsave);
13793 }
13794
13795 /*-----------------------------------------------------------------*/
13796 /* genSystemProcessResume -                                        */
13797 /*-----------------------------------------------------------------*/
13798 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13799 {
13800         bitVect *rsave ;
13801         operand *pid;
13802
13803         assert (nparms==1);
13804         /* save registers that need to be saved */
13805         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13806                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13807
13808         pid = parms[0];
13809
13810         /* pid into ACC */
13811         aopOp(pid,ic,FALSE,FALSE);
13812         emitcode ("mov","a,%s",
13813                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13814         freeAsmop (pid, NULL, ic, FALSE);
13815
13816         emitcode ("lcall","System_ProcessResume");
13817
13818         unsavermask(rsave);
13819 }
13820
13821 /*-----------------------------------------------------------------*/
13822 /* genSystem -                                                     */
13823 /*-----------------------------------------------------------------*/
13824 static void genSystem (iCode *ic,int nparms,char *name)
13825 {
13826         assert(nparms == 0);
13827
13828         emitcode ("lcall","System_%s",name);
13829 }
13830
13831 /*-----------------------------------------------------------------*/
13832 /* genSystemPoll -                                                  */
13833 /*-----------------------------------------------------------------*/
13834 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13835 {
13836         bitVect *rsave ;
13837         operand *fp;
13838
13839         assert (nparms==1);
13840         /* save registers that need to be saved */
13841         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13842                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13843
13844         fp = parms[0];
13845         aopOp (fp,ic,FALSE,FALSE);
13846         if (AOP_TYPE (fp) == AOP_IMMD) {
13847                 emitcode ("mov", "dptr,%s",
13848                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13849         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13850                 emitcode ("mov","dpl,%s",
13851                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13852                 emitcode ("mov","dph,%s",
13853                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13854                 emitcode ("mov","dpx,%s",
13855                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13856         }
13857         freeAsmop (fp, NULL, ic, FALSE);
13858
13859         emitcode ("lcall","System_%sPoll",name);
13860
13861         /* put result into place */
13862         {
13863                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13864                 if (rsym->liveFrom != rsym->liveTo) {
13865                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13866                         aopPut(IC_RESULT(ic),"a",0);
13867                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13868                 }
13869         }
13870         unsavermask(rsave);
13871 }
13872
13873 /*-----------------------------------------------------------------*/
13874 /* genSystemGetCurrentID -                                         */
13875 /*-----------------------------------------------------------------*/
13876 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13877 {
13878         assert (nparms==0);
13879
13880         emitcode ("lcall","System_GetCurrent%sId",name);
13881         /* put result into place */
13882         {
13883                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13884                 if (rsym->liveFrom != rsym->liveTo) {
13885                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13886                         aopPut(IC_RESULT(ic),"a",0);
13887                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13888                 }
13889         }
13890 }
13891
13892 /*-----------------------------------------------------------------*/
13893 /* genDjnz - generate decrement & jump if not zero instrucion      */
13894 /*-----------------------------------------------------------------*/
13895 static int
13896 genDjnz (iCode * ic, iCode * ifx)
13897 {
13898   symbol *lbl, *lbl1;
13899   if (!ifx)
13900     return 0;
13901
13902   /* if the if condition has a false label
13903      then we cannot save */
13904   if (IC_FALSE (ifx))
13905     return 0;
13906
13907   /* if the minus is not of the form a = a - 1 */
13908   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13909       !IS_OP_LITERAL (IC_RIGHT (ic)))
13910     return 0;
13911
13912   if (operandLitValue (IC_RIGHT (ic)) != 1)
13913     return 0;
13914
13915   /* if the size of this greater than one then no
13916      saving */
13917   if (getSize (operandType (IC_RESULT (ic))) > 1)
13918     return 0;
13919
13920   /* otherwise we can save BIG */
13921
13922   D (emitcode (";", "genDjnz"));
13923
13924   lbl = newiTempLabel (NULL);
13925   lbl1 = newiTempLabel (NULL);
13926
13927   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13928
13929   if (AOP_NEEDSACC(IC_RESULT(ic)))
13930   {
13931       /* If the result is accessed indirectly via
13932        * the accumulator, we must explicitly write
13933        * it back after the decrement.
13934        */
13935       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13936
13937       if (strcmp(rByte, "a"))
13938       {
13939            /* Something is hopelessly wrong */
13940            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13941                    __FILE__, __LINE__);
13942            /* We can just give up; the generated code will be inefficient,
13943             * but what the hey.
13944             */
13945            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13946            return 0;
13947       }
13948       emitcode ("dec", "%s", rByte);
13949       aopPut (IC_RESULT (ic), rByte, 0);
13950       emitcode ("jnz", "!tlabel", lbl->key + 100);
13951   }
13952   else if (IS_AOP_PREG (IC_RESULT (ic)))
13953     {
13954       emitcode ("dec", "%s",
13955                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13956       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13957       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13958       ifx->generated = 1;
13959       emitcode ("jnz", "!tlabel", lbl->key + 100);
13960     }
13961   else
13962     {
13963       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13964                 lbl->key + 100);
13965     }
13966   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13967   emitLabel (lbl);
13968   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13969   emitLabel (lbl1);
13970
13971   if (!ifx->generated)
13972       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13973   ifx->generated = 1;
13974   return 1;
13975 }
13976
13977 /*-----------------------------------------------------------------*/
13978 /* genReceive - generate code for a receive iCode                  */
13979 /*-----------------------------------------------------------------*/
13980 static void
13981 genReceive (iCode * ic)
13982 {
13983   int size = getSize (operandType (IC_RESULT (ic)));
13984   int offset = 0;
13985   int rb1off ;
13986
13987   D (emitcode (";", "genReceive"));
13988
13989   if (ic->argreg == 1)
13990     {
13991       /* first parameter */
13992       if (AOP_IS_STR(IC_RESULT(ic)))
13993         {
13994           /* Nothing to do: it's already in the proper place. */
13995           return;
13996         }
13997       else
13998         {
13999           bool useDp2;
14000
14001           useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
14002                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
14003                  IS_TRUE_SYMOP (IC_RESULT (ic)));
14004
14005           _G.accInUse++;
14006           aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
14007           _G.accInUse--;
14008
14009           /* Sanity checking... */
14010           if (AOP_USESDPTR(IC_RESULT(ic)))
14011             {
14012               werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14013                       "genReceive got unexpected DPTR.");
14014             }
14015           assignResultValue (IC_RESULT (ic), NULL);
14016         }
14017     }
14018   else if (ic->argreg > 12)
14019     { /* bit parameters */
14020       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
14021         {
14022           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
14023           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
14024           outBitC(IC_RESULT (ic));
14025         }
14026     }
14027   else
14028     {
14029       /* second receive onwards */
14030       /* this gets a little tricky since unused receives will be
14031        eliminated, we have saved the reg in the type field . and
14032        we use that to figure out which register to use */
14033       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
14034       rb1off = ic->argreg;
14035       while (size--)
14036         {
14037           aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
14038         }
14039     }
14040   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14041 }
14042
14043 /*-----------------------------------------------------------------*/
14044 /* genDummyRead - generate code for dummy read of volatiles        */
14045 /*-----------------------------------------------------------------*/
14046 static void
14047 genDummyRead (iCode * ic)
14048 {
14049   operand *op;
14050   int size, offset;
14051
14052   D (emitcode(";", "genDummyRead"));
14053
14054   op = IC_RIGHT (ic);
14055   if (op && IS_SYMOP (op))
14056     {
14057       aopOp (op, ic, FALSE, FALSE);
14058
14059       /* if the result is a bit */
14060       if (AOP_TYPE (op) == AOP_CRY)
14061         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14062       else
14063         {
14064           /* bit variables done */
14065           /* general case */
14066           size = AOP_SIZE (op);
14067           offset = 0;
14068           while (size--)
14069           {
14070             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14071             offset++;
14072           }
14073         }
14074
14075       freeAsmop (op, NULL, ic, TRUE);
14076     }
14077
14078   op = IC_LEFT (ic);
14079   if (op && IS_SYMOP (op))
14080     {
14081       aopOp (op, ic, FALSE, FALSE);
14082
14083       /* if the result is a bit */
14084       if (AOP_TYPE (op) == AOP_CRY)
14085         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14086       else
14087         {
14088           /* bit variables done */
14089           /* general case */
14090           size = AOP_SIZE (op);
14091           offset = 0;
14092           while (size--)
14093           {
14094             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14095             offset++;
14096           }
14097         }
14098
14099       freeAsmop (op, NULL, ic, TRUE);
14100     }
14101 }
14102
14103 /*-----------------------------------------------------------------*/
14104 /* genCritical - generate code for start of a critical sequence    */
14105 /*-----------------------------------------------------------------*/
14106 static void
14107 genCritical (iCode *ic)
14108 {
14109   symbol *tlbl = newiTempLabel (NULL);
14110
14111   D (emitcode(";", "genCritical"));
14112
14113   if (IC_RESULT (ic))
14114     {
14115       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14116       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14117       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14118       aopPut (IC_RESULT (ic), zero, 0);
14119       emitLabel (tlbl);
14120       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14121     }
14122   else
14123     {
14124       emitcode ("setb", "c");
14125       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14126       emitcode ("clr", "c");
14127       emitLabel (tlbl);
14128       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14129     }
14130 }
14131
14132 /*-----------------------------------------------------------------*/
14133 /* genEndCritical - generate code for end of a critical sequence   */
14134 /*-----------------------------------------------------------------*/
14135 static void
14136 genEndCritical (iCode *ic)
14137 {
14138   D(emitcode(";", "genEndCritical"));
14139
14140   if (IC_RIGHT (ic))
14141     {
14142       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14143       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14144         {
14145           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14146           emitcode ("mov", "ea,c");
14147         }
14148       else
14149         {
14150           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14151           emitcode ("rrc", "a");
14152           emitcode ("mov", "ea,c");
14153         }
14154       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14155     }
14156   else
14157     {
14158       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14159       emitcode ("mov", "ea,c");
14160     }
14161 }
14162
14163
14164
14165 /*-----------------------------------------------------------------*/
14166 /* genBuiltIn - calls the appropriate function to  generating code */
14167 /* for a built in function                                         */
14168 /*-----------------------------------------------------------------*/
14169 static void genBuiltIn (iCode *ic)
14170 {
14171         operand *bi_parms[MAX_BUILTIN_ARGS];
14172         int nbi_parms;
14173         iCode *bi_iCode;
14174         symbol *bif;
14175
14176         /* get all the arguments for a built in function */
14177         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14178
14179         /* which function is it */
14180         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14181         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14182                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14183         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14184                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14185         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14186                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14187         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14188                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14189         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14190                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14191         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14192                 genInp(bi_iCode,nbi_parms,bi_parms);
14193         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14194                 genOutp(bi_iCode,nbi_parms,bi_parms);
14195         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14196                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14197                 /* JavaNative builtIns */
14198         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14199                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14200         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14201                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14202         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14203                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14204         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14205                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14206         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14207                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14208         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14209                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14210         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14211                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14212         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14213                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14214         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14215                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14216         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14217                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14218         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14219                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14220         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14221                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14222         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14223                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14224         } else if (strcmp(bif->name,"MM_Free")==0) {
14225                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14226         } else if (strcmp(bif->name,"MM_Deref")==0) {
14227                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14228         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14229                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14230         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14231                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14232         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14233                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14234         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14235                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14236         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14237                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14238         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14239                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14240         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14241                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14242         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14243                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14244         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14245                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14246         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14247                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14248         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14249                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14250         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14251                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14252         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14253                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14254         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14255                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14256         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14257                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14258         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14259                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14260         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14261                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14262         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14263                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14264         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14265                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14266         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14267                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14268         } else {
14269                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14270                 return ;
14271         }
14272         return ;
14273 }
14274
14275 /*-----------------------------------------------------------------*/
14276 /* gen390Code - generate code for Dallas 390 based controllers     */
14277 /*-----------------------------------------------------------------*/
14278 void
14279 gen390Code (iCode * lic)
14280 {
14281   iCode *ic;
14282   int cln = 0;
14283
14284   _G.currentFunc = NULL;
14285   lineHead = lineCurr = NULL;
14286   dptrn[1][0] = "dpl1";
14287   dptrn[1][1] = "dph1";
14288   dptrn[1][2] = "dpx1";
14289
14290   if (options.model == MODEL_FLAT24) {
14291     fReturnSizeDS390 = 5;
14292     fReturn = fReturn24;
14293   } else {
14294     fReturnSizeDS390 = 4;
14295     fReturn = fReturn16;
14296     options.stack10bit=0;
14297   }
14298 #if 1
14299   /* print the allocation information */
14300   if (allocInfo && currFunc)
14301     printAllocInfo (currFunc, codeOutBuf);
14302 #endif
14303   /* if debug information required */
14304   if (options.debug && currFunc)
14305     {
14306       debugFile->writeFunction (currFunc, lic);
14307     }
14308   /* stack pointer name */
14309   if (options.useXstack)
14310     spname = "_spx";
14311   else
14312     spname = "sp";
14313
14314
14315   for (ic = lic; ic; ic = ic->next)
14316     {
14317       _G.current_iCode = ic;
14318
14319       if (ic->lineno && cln != ic->lineno)
14320         {
14321           if (options.debug)
14322             {
14323               debugFile->writeCLine (ic);
14324             }
14325           if (!options.noCcodeInAsm) {
14326             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14327                       printCLine(ic->filename, ic->lineno));
14328           }
14329           cln = ic->lineno;
14330         }
14331       if (options.iCodeInAsm) {
14332         const char *iLine = printILine(ic);
14333         emitcode(";", "ic:%d: %s", ic->key, iLine);
14334         dbuf_free(iLine);
14335       }
14336       /* if the result is marked as
14337          spilt and rematerializable or code for
14338          this has already been generated then
14339          do nothing */
14340       if (resultRemat (ic) || ic->generated)
14341         continue;
14342
14343       /* depending on the operation */
14344       switch (ic->op)
14345         {
14346         case '!':
14347           genNot (ic);
14348           break;
14349
14350         case '~':
14351           genCpl (ic);
14352           break;
14353
14354         case UNARYMINUS:
14355           genUminus (ic);
14356           break;
14357
14358         case IPUSH:
14359           genIpush (ic);
14360           break;
14361
14362         case IPOP:
14363           {
14364             iCode *ifxIc, *popIc;
14365             bool CommonRegs = FALSE;
14366
14367             /* IPOP happens only when trying to restore a
14368                spilt live range, if there is an ifx statement
14369                following this pop (or several) then the if statement might
14370                be using some of the registers being popped which
14371                would destory the contents of the register so
14372                we need to check for this condition and handle it */
14373             for (ifxIc = ic->next; ifxIc && ifxIc->op == IPOP; ifxIc = ifxIc->next);
14374             for (popIc = ic; popIc && popIc->op == IPOP; popIc = popIc->next)
14375               CommonRegs |= (ifxIc && ifxIc->op == IFX && !ifxIc->generated &&
14376                              regsInCommon (IC_LEFT (popIc), IC_COND (ifxIc)));
14377             if (CommonRegs)
14378               genIfx (ifxIc, ic);
14379             else
14380               genIpop (ic);
14381           }
14382           break;
14383
14384         case CALL:
14385           genCall (ic);
14386           break;
14387
14388         case PCALL:
14389           genPcall (ic);
14390           break;
14391
14392         case FUNCTION:
14393           genFunction (ic);
14394           break;
14395
14396         case ENDFUNCTION:
14397           genEndFunction (ic);
14398           break;
14399
14400         case RETURN:
14401           genRet (ic);
14402           break;
14403
14404         case LABEL:
14405           genLabel (ic);
14406           break;
14407
14408         case GOTO:
14409           genGoto (ic);
14410           break;
14411
14412         case '+':
14413           genPlus (ic);
14414           break;
14415
14416         case '-':
14417           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14418             genMinus (ic);
14419           break;
14420
14421         case '*':
14422           genMult (ic);
14423           break;
14424
14425         case '/':
14426           genDiv (ic);
14427           break;
14428
14429         case '%':
14430           genMod (ic);
14431           break;
14432
14433         case '>':
14434           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14435           break;
14436
14437         case '<':
14438           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14439           break;
14440
14441         case LE_OP:
14442         case GE_OP:
14443         case NE_OP:
14444
14445           /* note these two are xlated by algebraic equivalence
14446              during parsing SDCC.y */
14447           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14448                   "got '>=' or '<=' shouldn't have come here");
14449           break;
14450
14451         case EQ_OP:
14452           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14453           break;
14454
14455         case AND_OP:
14456           genAndOp (ic);
14457           break;
14458
14459         case OR_OP:
14460           genOrOp (ic);
14461           break;
14462
14463         case '^':
14464           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14465           break;
14466
14467         case '|':
14468           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14469           break;
14470
14471         case BITWISEAND:
14472           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14473           break;
14474
14475         case INLINEASM:
14476           genInline (ic);
14477           break;
14478
14479         case RRC:
14480           genRRC (ic);
14481           break;
14482
14483         case RLC:
14484           genRLC (ic);
14485           break;
14486
14487         case GETHBIT:
14488           genGetHbit (ic);
14489           break;
14490
14491         case LEFT_OP:
14492           genLeftShift (ic);
14493           break;
14494
14495         case RIGHT_OP:
14496           genRightShift (ic);
14497           break;
14498
14499         case GET_VALUE_AT_ADDRESS:
14500           genPointerGet (ic,
14501                          hasInc (IC_LEFT (ic), ic,
14502                                  getSize (operandType (IC_RESULT (ic)))));
14503           break;
14504
14505         case '=':
14506           if (POINTER_SET (ic))
14507             genPointerSet (ic,
14508                            hasInc (IC_RESULT (ic), ic,
14509                                    getSize (operandType (IC_RIGHT (ic)))));
14510           else
14511             genAssign (ic);
14512           break;
14513
14514         case IFX:
14515           genIfx (ic, NULL);
14516           break;
14517
14518         case ADDRESS_OF:
14519           genAddrOf (ic);
14520           break;
14521
14522         case JUMPTABLE:
14523           genJumpTab (ic);
14524           break;
14525
14526         case CAST:
14527           genCast (ic);
14528           break;
14529
14530         case RECEIVE:
14531           genReceive (ic);
14532           break;
14533
14534         case SEND:
14535           if (ic->builtinSEND)
14536             genBuiltIn(ic);
14537           else
14538             addSet (&_G.sendSet, ic);
14539           break;
14540
14541         case DUMMY_READ_VOLATILE:
14542           genDummyRead (ic);
14543           break;
14544
14545         case CRITICAL:
14546           genCritical (ic);
14547           break;
14548
14549         case ENDCRITICAL:
14550           genEndCritical (ic);
14551           break;
14552
14553         case SWAP:
14554           genSwap (ic);
14555           break;
14556
14557 #if 0 // obsolete, and buggy for != xdata
14558         case ARRAYINIT:
14559             genArrayInit(ic);
14560             break;
14561 #endif
14562
14563         default:
14564             /* This should never happen, right? */
14565             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n",
14566                     ic->op, ic->op, __FILE__, __LINE__);
14567             ic = ic;
14568         }
14569     }
14570
14571
14572   /* now we are ready to call the
14573      peep hole optimizer */
14574   if (!options.nopeep)
14575     peepHole (&lineHead);
14576
14577   /* now do the actual printing */
14578   printLine (lineHead, codeOutBuf);
14579   return;
14580 }