761b4a9d3cea90939a60f918c93ec4bbd3e8b2b3
[fw/sdcc] / src / ds390 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - source file for code generation for DS80C390
3
4   Written By -  Sandeep Dutta . sandeep.dutta@usa.net (1998)
5          and -  Jean-Louis VERN.jlvern@writeme.com (1999)
6   Bug Fixes  -  Wojciech Stryjewski  wstryj1@tiger.lsu.edu (1999 v2.1.9a)
7   DS390 adaptation by Kevin Vigor <kevin@vigor.nu>
8
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22
23   In other words, you are welcome to use, share and improve this program.
24   You are forbidden to forbid anyone else to use, share and improve
25   what you give them.   Help stamp out software-hoarding!
26 -------------------------------------------------------------------------*/
27
28 //#define D(x)
29 #define D(x) do if (options.verboseAsm) {x;} while(0)
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include "SDCCglobl.h"
36 #include "newalloc.h"
37 #include "dbuf_string.h"
38
39 #include "common.h"
40 #include "main.h"
41 #include "ralloc.h"
42 #include "gen.h"
43
44 #define BETTER_LITERAL_SHIFT
45
46 char *aopLiteral (value * val, int offset);
47 extern int allocInfo;
48
49 /* this is the down and dirty file with all kinds of
50    kludgy & hacky stuff. This is what it is all about
51    CODE GENERATION for a specific MCU . some of the
52    routines may be reusable, will have to see */
53
54 static char *zero = "#0";
55 static char *one = "#1";
56 static char *spname;
57
58 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
59 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
60
61 unsigned fReturnSizeDS390 = 5;
62 static char *fReturn24[] =
63 {"dpl", "dph", "dpx", "b", "a"};
64 static char *fReturn16[] =
65 {"dpl", "dph", "b", "a"};
66 static char **fReturn = fReturn24;
67 static char *accUse[] =
68 {"a", "b"};
69 static char *dptrn[2][3];
70 static char *javaRet[] = { "r0","r1","r2","r3"};
71 static short rbank = -1;
72
73 #define REG_WITH_INDEX   ds390_regWithIdx
74
75 #define AOP(op) op->aop
76 #define AOP_TYPE(op) AOP(op)->type
77 #define AOP_SIZE(op) AOP(op)->size
78 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
79                        AOP_TYPE(x) == AOP_R0))
80
81 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
82                          AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
83                          AOP(x)->paged))
84
85 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
86                        (x->aopu.aop_reg[0] == REG_WITH_INDEX(R0_IDX) || \
87                         x->aopu.aop_reg[0] == REG_WITH_INDEX(R1_IDX) )))
88 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
89 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
90 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
91
92 // The following two macros can be used even if the aop has not yet been aopOp'd.
93 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
94 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
95
96 /* Workaround for DS80C390 bug: div ab may return bogus results
97  * if A is accessed in instruction immediately before the div.
98  *
99  * Will be fixed in B4 rev of processor, Dallas claims.
100  */
101
102 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
103     if (!AOP_NEEDSACC(RIGHT))         \
104     {               \
105       /* We can load A first, then B, since     \
106        * B (the RIGHT operand) won't clobber A,   \
107        * thus avoiding touching A right before the div. \
108        */             \
109       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
110       L = aopGet(LEFT,0,FALSE,FALSE,NULL);     \
111       MOVA(L);            \
112       L = aopGet(RIGHT,0,FALSE,FALSE,"b"); \
113       MOVB(L); \
114     }               \
115     else              \
116     {               \
117       /* Just stuff in a nop after loading A. */    \
118       emitcode("mov","b,%s",aopGet(RIGHT,0,FALSE,FALSE,NULL));\
119       L = aopGet(LEFT,0,FALSE,FALSE,NULL);   \
120       MOVA(L);            \
121       emitcode("nop", "; workaround for DS80C390 div bug.");  \
122     }
123
124 #define R0INB   _G.bu.bs.r0InB
125 #define R1INB   _G.bu.bs.r1InB
126 #define OPINB   _G.bu.bs.OpInB
127 #define BINUSE  _G.bu.BInUse
128
129 static struct
130   {
131     short r0Pushed;
132     short r1Pushed;
133     union
134       {
135         struct
136           {
137             short r0InB : 2;//2 so we can see it overflow
138             short r1InB : 2;//2 so we can see it overflow
139             short OpInB : 2;//2 so we can see it overflow
140           } bs;
141         short BInUse;
142       } bu;
143     short accInUse;
144     short inLine;
145     short debugLine;
146     short nRegsSaved;
147     short dptrInUse;
148     short dptr1InUse;
149     set *sendSet;
150     iCode *current_iCode;
151     symbol *currentFunc;
152   }
153 _G;
154
155 static char *rb1regs[] = {
156     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7",
157     "b0",  "b1",  "b2",  "b3",  "b4",  "b5",  "b6",  "b7"
158 };
159
160 static void saveRBank (int, iCode *, bool);
161
162 #define RESULTONSTACK(x) \
163                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
164                          IC_RESULT(x)->aop->type == AOP_STK )
165
166 #define MOVA(x)  mova(x)  /* use function to avoid multiple eval */
167 #define MOVB(x)  movb(x)
168
169 #define CLRC    emitcode("clr","c")
170 #define SETC    emitcode("setb","c")
171
172 // A scratch register which will be used to hold
173 // result bytes from operands in far space via DPTR2.
174 #define DP2_RESULT_REG  "_ap"
175
176 static lineNode *lineHead = NULL;
177 static lineNode *lineCurr = NULL;
178
179 static unsigned char SLMask[] =
180 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
181  0xE0, 0xC0, 0x80, 0x00};
182 static unsigned char SRMask[] =
183 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
184  0x07, 0x03, 0x01, 0x00};
185
186 #define LSB     0
187 #define MSB16   1
188 #define MSB24   2
189 #define MSB32   3
190 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
191                                 symbol *lbl = newiTempLabel(NULL);              \
192                                 emitcode ("setb","F1");                         \
193                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
194                                 emitcode ("clr","F1");                          \
195                                 emitLabel (lbl);                                \
196                         }}
197 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
198                                 emitcode ("mov","EA,F1");                       \
199                         }}
200
201 static int _currentDPS;         /* Current processor DPS. */
202 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
203 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
204
205 /*-----------------------------------------------------------------*/
206 /* emitcode - writes the code into a file : for now it is simple    */
207 /*-----------------------------------------------------------------*/
208 static void
209 emitcode (const char *inst, const char *fmt,...)
210 {
211   va_list ap;
212   struct dbuf_s dbuf;
213   const char *lbp, *lb;
214
215   dbuf_init (&dbuf, INITIAL_INLINEASM);
216
217   va_start (ap, fmt);
218
219   if (inst && *inst)
220     {
221       dbuf_append_str (&dbuf, inst);
222
223       if (fmt && *fmt)
224         {
225           dbuf_append_char (&dbuf, '\t');
226           dbuf_tvprintf (&dbuf, fmt, ap);
227       }
228     }
229   else
230     {
231       dbuf_tvprintf (&dbuf, fmt, ap);
232     }
233
234   lbp = lb = dbuf_c_str(&dbuf);
235
236   while (isspace ((unsigned char)*lbp))
237     {
238       lbp++;
239     }
240
241   if (lbp)
242     {
243       lineCurr = (lineCurr ?
244                   connectLine (lineCurr, newLineNode (lb)) :
245                   (lineHead = newLineNode (lb)));
246
247       lineCurr->isInline = _G.inLine;
248       lineCurr->isDebug = _G.debugLine;
249       lineCurr->ic = _G.current_iCode;
250       lineCurr->aln = ds390newAsmLineNode(_currentDPS);
251       lineCurr->isComment = (*lbp == ';');
252     }
253
254   va_end (ap);
255
256   dbuf_destroy(&dbuf);
257 }
258
259 static void
260 emitLabel (symbol *tlbl)
261 {
262   emitcode ("", "!tlabeldef", tlbl->key + 100);
263   lineCurr->isLabel = 1;
264 }
265
266 /*-----------------------------------------------------------------*/
267 /* ds390_emitDebuggerSymbol - associate the current code location  */
268 /*   with a debugger symbol                                        */
269 /*-----------------------------------------------------------------*/
270 void
271 ds390_emitDebuggerSymbol (char * debugSym)
272 {
273   _G.debugLine = 1;
274   emitcode ("", "%s ==.", debugSym);
275   _G.debugLine = 0;
276 }
277
278 /*-----------------------------------------------------------------*/
279 /* mova - moves specified value into accumulator                   */
280 /*-----------------------------------------------------------------*/
281 static void
282 mova (const char *x)
283 {
284   /* do some early peephole optimization */
285   if (!strncmp(x, "a", 2) || !strncmp(x, "acc", 4))
286     return;
287
288   emitcode("mov", "a,%s", x);
289 }
290
291 /*-----------------------------------------------------------------*/
292 /* movb - moves specified value into register b                    */
293 /*-----------------------------------------------------------------*/
294 static void
295 movb (const char *x)
296 {
297   /* do some early peephole optimization */
298   if (!strncmp(x, "b", 2))
299     return;
300
301   emitcode("mov","b,%s", x);
302 }
303
304 /*-----------------------------------------------------------------*/
305 /* movc - moves specified value into the carry                     */
306 /*-----------------------------------------------------------------*/
307 static void
308 movc (const char *s)
309 {
310   if (s == zero)
311     CLRC;
312   else if (s == one)
313     SETC;
314   else if (strcmp (s, "c"))
315     {/* it's not in carry already */
316       MOVA (s);
317       /* set C, if a >= 1 */
318       emitcode ("add", "a,#0xff");
319     }
320 }
321
322 /*-----------------------------------------------------------------*/
323 /* pushB - saves register B if necessary                           */
324 /*-----------------------------------------------------------------*/
325 static bool
326 pushB (void)
327 {
328   bool pushedB = FALSE;
329
330   if (BINUSE)
331     {
332       emitcode ("push", "b");
333 //    printf("B was in use !\n");
334       pushedB = TRUE;
335     }
336   else
337     {
338       OPINB++;
339     }
340   return pushedB;
341 }
342
343 /*-----------------------------------------------------------------*/
344 /* popB - restores value of register B if necessary                */
345 /*-----------------------------------------------------------------*/
346 static void
347 popB (bool pushedB)
348 {
349   if (pushedB)
350     {
351       emitcode ("pop", "b");
352     }
353   else
354     {
355       OPINB--;
356     }
357 }
358
359 /*-----------------------------------------------------------------*/
360 /* pushReg - saves register                                        */
361 /*-----------------------------------------------------------------*/
362 static bool
363 pushReg (int index, bool bits_pushed)
364 {
365   regs * reg = REG_WITH_INDEX (index);
366   if (reg->type == REG_BIT)
367     {
368       if (!bits_pushed)
369         emitcode ("push", "%s", reg->base);
370       return TRUE;
371     }
372   else
373     emitcode ("push", "%s", reg->dname);
374   return bits_pushed;
375 }
376
377 /*-----------------------------------------------------------------*/
378 /* popReg - restores register                                      */
379 /*-----------------------------------------------------------------*/
380 static bool
381 popReg (int index, bool bits_popped)
382 {
383   regs * reg = REG_WITH_INDEX (index);
384   if (reg->type == REG_BIT)
385     {
386       if (!bits_popped)
387         emitcode ("pop", "%s", reg->base);
388       return TRUE;
389     }
390   else
391     emitcode ("pop", "%s", reg->dname);
392   return bits_popped;
393 }
394
395 /*-----------------------------------------------------------------*/
396 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
397 /*-----------------------------------------------------------------*/
398 static regs *
399 getFreePtr (iCode * ic, asmop ** aopp, bool result)
400 {
401   bool r0iu, r1iu;
402   bool r0ou, r1ou;
403
404   /* the logic: if r0 & r1 used in the instruction
405      then we are in trouble otherwise */
406
407   /* first check if r0 & r1 are used by this
408      instruction, in which case we are in trouble */
409   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
410   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
411   if (r0iu && r1iu) {
412       goto endOfWorld;
413     }
414
415   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
416   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
417
418   /* if no usage of r0 then return it */
419   if (!r0iu && !r0ou)
420     {
421       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
422       (*aopp)->type = AOP_R0;
423
424       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
425     }
426
427   /* if no usage of r1 then return it */
428   if (!r1iu && !r1ou)
429     {
430       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
431       (*aopp)->type = AOP_R1;
432
433       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R1_IDX);
434     }
435
436   /* now we know they both have usage */
437   /* if r0 not used in this instruction */
438   if (!r0iu)
439     {
440       /* push it if not already pushed */
441       if (!_G.r0Pushed)
442         {
443           emitcode ("push", "%s",
444                     REG_WITH_INDEX (R0_IDX)->dname);
445           _G.r0Pushed++;
446         }
447
448       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
449       (*aopp)->type = AOP_R0;
450
451       return (*aopp)->aopu.aop_ptr = REG_WITH_INDEX (R0_IDX);
452     }
453
454   /* if r1 not used then */
455
456   if (!r1iu)
457     {
458       /* push it if not already pushed */
459       if (!_G.r1Pushed)
460         {
461           emitcode ("push", "%s",
462                     REG_WITH_INDEX (R1_IDX)->dname);
463           _G.r1Pushed++;
464         }
465
466       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
467       (*aopp)->type = AOP_R1;
468       return REG_WITH_INDEX (R1_IDX);
469     }
470
471 endOfWorld:
472   /* I said end of world, but not quite end of world yet */
473   /* if this is a result then we can push it on the stack */
474   if (result)
475     {
476       (*aopp)->type = AOP_STK;
477       return NULL;
478     }
479
480   /* now this is REALLY the end of the world */
481   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
482           "getFreePtr should never reach here");
483   exit (1);
484
485   return NULL; // notreached, but makes compiler happy.
486 }
487
488
489 /*-----------------------------------------------------------------*/
490 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
491 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
492 /* alternate DPTR (DPL1/DPH1/DPX1).                                */
493 /*-----------------------------------------------------------------*/
494 static void
495 genSetDPTR (int n)
496 {
497
498   /* If we are doing lazy evaluation, simply note the desired
499    * change, but don't emit any code yet.
500    */
501   if (_lazyDPS)
502     {
503       _desiredDPS = n;
504       return;
505     }
506
507   if (!n)
508     {
509       emitcode ("mov", "dps,#0");
510     }
511   else
512     {
513       TR_DPTR("#1");
514       emitcode ("mov", "dps,#1");
515     }
516 }
517
518 /*------------------------------------------------------------------*/
519 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
520 /*                                                                  */
521 /* Any code that operates on DPTR (NB: not on the individual        */
522 /* components, like DPH) *must* call _flushLazyDPS() before using   */
523 /* DPTR within a lazy DPS evaluation block.                         */
524 /*                                                                  */
525 /* Note that aopPut and aopGet already contain the proper calls to  */
526 /* _flushLazyDPS, so it is safe to use these calls within a lazy    */
527 /* DPS evaluation block.                                            */
528 /*                                                                  */
529 /* Also, _flushLazyDPS must be called before any flow control       */
530 /* operations that could potentially branch out of the block.       */
531 /*                                                                  */
532 /* Lazy DPS evaluation is simply an optimization (though an         */
533 /* important one), so if in doubt, leave it out.                    */
534 /*------------------------------------------------------------------*/
535 static void
536 _startLazyDPSEvaluation (void)
537 {
538   _currentDPS = 0;
539   _desiredDPS = 0;
540 #ifdef BETTER_LITERAL_SHIFT
541   _lazyDPS++;
542 #else
543   _lazyDPS = 1;
544 #endif
545 }
546
547 /*------------------------------------------------------------------*/
548 /* _flushLazyDPS: emit code to force the actual DPS setting to the  */
549 /* desired one. Call before using DPTR within a lazy DPS evaluation */
550 /* block.                                                           */
551 /*------------------------------------------------------------------*/
552 static void
553 _flushLazyDPS (void)
554 {
555   if (!_lazyDPS)
556     {
557       /* nothing to do. */
558       return;
559     }
560
561   if (_desiredDPS != _currentDPS)
562     {
563       if (_desiredDPS)
564         {
565           emitcode ("inc", "dps");
566         }
567       else
568         {
569           emitcode ("dec", "dps");
570         }
571       _currentDPS = _desiredDPS;
572     }
573 }
574
575 /*-----------------------------------------------------------------*/
576 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.           */
577 /*                                                                 */
578 /* Forces us back to the safe state (standard DPTR selected).      */
579 /*-----------------------------------------------------------------*/
580 static void
581 _endLazyDPSEvaluation (void)
582 {
583 #ifdef BETTER_LITERAL_SHIFT
584   _lazyDPS--;
585 #else
586   _lazyDPS = 0;
587 #endif
588   if (!_lazyDPS)
589   {
590     if (_currentDPS)
591     {
592       genSetDPTR (0);
593       _flushLazyDPS ();
594     }
595     _currentDPS = 0;
596     _desiredDPS = 0;
597   }
598 }
599
600
601 /*-----------------------------------------------------------------*/
602 /* newAsmop - creates a new asmOp                                  */
603 /*-----------------------------------------------------------------*/
604 static asmop *
605 newAsmop (short type)
606 {
607   asmop *aop;
608
609   aop = Safe_calloc (1, sizeof (asmop));
610   aop->type = type;
611   aop->allocated = 1;
612   return aop;
613 }
614
615 /*-----------------------------------------------------------------*/
616 /* pointerCode - returns the code for a pointer type               */
617 /*-----------------------------------------------------------------*/
618 static int
619 pointerCode (sym_link * etype)
620 {
621
622   return PTR_TYPE (SPEC_OCLS (etype));
623
624 }
625
626 /*-----------------------------------------------------------------*/
627 /* leftRightUseAcc - returns size of accumulator use by operands   */
628 /*-----------------------------------------------------------------*/
629 static int
630 leftRightUseAcc(iCode *ic)
631 {
632   operand *op;
633   int size;
634   int accuseSize = 0;
635   int accuse = 0;
636
637   if (!ic)
638     {
639       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
640               "null iCode pointer");
641       return 0;
642     }
643
644   if (ic->op == IFX)
645     {
646       op = IC_COND (ic);
647       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
648         {
649           accuse = 1;
650           size = getSize (OP_SYMBOL (op)->type);
651           if (size>accuseSize)
652             accuseSize = size;
653         }
654     }
655   else if (ic->op == JUMPTABLE)
656     {
657       op = IC_JTCOND (ic);
658       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
659         {
660           accuse = 1;
661           size = getSize (OP_SYMBOL (op)->type);
662           if (size>accuseSize)
663             accuseSize = size;
664         }
665     }
666   else
667     {
668       op = IC_LEFT (ic);
669       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
670         {
671           accuse = 1;
672           size = getSize (OP_SYMBOL (op)->type);
673           if (size>accuseSize)
674             accuseSize = size;
675         }
676       op = IC_RIGHT (ic);
677       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
678         {
679           accuse = 1;
680           size = getSize (OP_SYMBOL (op)->type);
681           if (size>accuseSize)
682             accuseSize = size;
683         }
684     }
685
686   if (accuseSize)
687     return accuseSize;
688   else
689     return accuse;
690 }
691
692 /*-----------------------------------------------------------------*/
693 /* aopForSym - for a true symbol                                   */
694 /*-----------------------------------------------------------------*/
695 static asmop *
696 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
697 {
698   asmop *aop;
699   memmap *space;
700   bool accuse = leftRightUseAcc (ic) || _G.accInUse;
701   char *dpl = useDP2 ? "dpl1" : "dpl";
702   char *dph = useDP2 ? "dph1" : "dph";
703   char *dpx = useDP2 ? "dpx1" : "dpx";
704
705   wassertl (ic != NULL, "Got a null iCode");
706   wassertl (sym != NULL, "Got a null symbol");
707
708   space = SPEC_OCLS (sym->etype);
709
710   /* if already has one */
711   if (sym->aop)
712     {
713       if ((sym->aop->type == AOP_DPTR && useDP2)
714           || (sym->aop->type == AOP_DPTR2 && !useDP2))
715         sym->aop = NULL;
716       else
717         {
718           sym->aop->allocated++;
719           return sym->aop;
720         }
721     }
722
723   /* assign depending on the storage class */
724   /* if it is on the stack or indirectly addressable */
725   /* space we need to assign either r0 or r1 to it   */
726   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
727     {
728       sym->aop = aop = newAsmop (0);
729       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
730       aop->size = getSize (sym->type);
731
732       /* now assign the address of the variable to
733          the pointer register */
734       if (aop->type != AOP_STK)
735         {
736           if (sym->onStack)
737             {
738               signed char offset = ((sym->stack < 0) ?
739                          ((signed char) (sym->stack - _G.nRegsSaved)) :
740                          ((signed char) sym->stack)) & 0xff;
741
742               if ((abs(offset) <= 3) ||
743                   (accuse && (abs(offset) <= 7)))
744                 {
745                   emitcode ("mov", "%s,_bp",
746                             aop->aopu.aop_ptr->name);
747                   while (offset < 0)
748                     {
749                       emitcode ("dec", aop->aopu.aop_ptr->name);
750                       offset++;
751                     }
752                   while (offset > 0)
753                     {
754                       emitcode ("inc", aop->aopu.aop_ptr->name);
755                       offset--;
756                     }
757                 }
758               else
759                 {
760                   if (accuse)
761                     emitcode ("push", "acc");
762                   emitcode ("mov", "a,_bp");
763                   emitcode ("add", "a,#!constbyte", offset);
764                   emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
765                   if (accuse)
766                     emitcode ("pop", "acc");
767                 }
768             }
769           else
770             {
771               emitcode ("mov", "%s,#%s",
772                         aop->aopu.aop_ptr->name,
773                         sym->rname);
774             }
775           aop->paged = space->paged;
776         }
777       else
778         aop->aopu.aop_stk = sym->stack;
779       return aop;
780     }
781
782   if (sym->onStack && options.stack10bit)
783     {
784       short stack_val = -((sym->stack < 0) ?
785                           ((short) (sym->stack - _G.nRegsSaved)) :
786                           ((short) sym->stack)) ;
787       if (_G.dptrInUse ) {
788           emitcode ("push",dpl);
789           emitcode ("push",dph);
790           emitcode ("push",dpx);
791       }
792       /* It's on the 10 bit stack, which is located in
793        * far data space.
794        */
795       if (stack_val < 0 && stack_val > -5)
796         { /* between -5 & -1 */
797           if (options.model == MODEL_FLAT24)
798             {
799               emitcode ("mov", "%s,#!constbyte", dpx,
800                         (options.stack_loc >> 16) & 0xff);
801             }
802           emitcode ("mov", "%s,_bpx+1", dph);
803           emitcode ("mov", "%s,_bpx", dpl);
804           if (useDP2) {
805               emitcode ("mov","dps,#1");
806           }
807           stack_val = -stack_val;
808           while (stack_val--) {
809               emitcode ("inc","dptr");
810           }
811           if (useDP2) {
812               emitcode("mov","dps,#0");
813           }
814         }
815       else
816         {
817           if (accuse)
818               emitcode ("push", "acc");
819
820           emitcode ("mov", "a,_bpx");
821           emitcode ("clr","c");
822           emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
823           emitcode ("mov","%s,a", dpl);
824           emitcode ("mov","a,_bpx+1");
825           emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
826           emitcode ("mov", "%s,a", dph);
827           if (options.model == MODEL_FLAT24)
828             {
829               emitcode ("mov", "%s,#!constbyte", dpx,
830                         (options.stack_loc >> 16) & 0xff);
831             }
832
833           if (accuse)
834               emitcode ("pop", "acc");
835         }
836       sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
837       aop->size = getSize (sym->type);
838       return aop;
839     }
840
841   /* if in bit space */
842   if (IN_BITSPACE (space))
843     {
844       sym->aop = aop = newAsmop (AOP_CRY);
845       aop->aopu.aop_dir = sym->rname;
846       aop->size = getSize (sym->type);
847       return aop;
848     }
849   /* if it is in direct space */
850   if (IN_DIRSPACE (space))
851     {
852       sym->aop = aop = newAsmop (AOP_DIR);
853       aop->aopu.aop_dir = sym->rname;
854       aop->size = getSize (sym->type);
855       return aop;
856     }
857
858   /* special case for a function */
859   if (IS_FUNC (sym->type) && !(sym->isitmp))
860     {
861       sym->aop = aop = newAsmop (AOP_IMMD);
862       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
863       aop->size = FPTRSIZE;
864       return aop;
865     }
866
867   /* only remaining is far space */
868   /* in which case DPTR gets the address */
869   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
870   if (useDP2)
871     {
872       genSetDPTR (1);
873       _flushLazyDPS ();
874       emitcode ("mov", "dptr,#%s", sym->rname);
875       genSetDPTR (0);
876     }
877   else
878     {
879       emitcode ("mov", "dptr,#%s", sym->rname);
880     }
881   aop->size = getSize (sym->type);
882
883   /* if it is in code space */
884   if (IN_CODESPACE (space))
885     aop->code = 1;
886
887   return aop;
888 }
889
890 /*-----------------------------------------------------------------*/
891 /* aopForRemat - rematerialzes an object                           */
892 /*-----------------------------------------------------------------*/
893 static asmop *
894 aopForRemat (symbol * sym)
895 {
896   iCode *ic = sym->rematiCode;
897   asmop *aop = newAsmop (AOP_IMMD);
898   int ptr_type = 0;
899   int val = 0;
900
901   for (;;)
902     {
903       if (ic->op == '+')
904         val += (int) operandLitValue (IC_RIGHT (ic));
905       else if (ic->op == '-')
906         val -= (int) operandLitValue (IC_RIGHT (ic));
907       else if (IS_CAST_ICODE(ic)) {
908               sym_link *from_type = operandType(IC_RIGHT(ic));
909               aop->aopu.aop_immd.from_cast_remat = 1;
910               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
911               ptr_type = pointerTypeToGPByte (DCL_TYPE(from_type), NULL, NULL);
912               continue;
913       } else break;
914
915       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
916     }
917
918   if (val)
919   {
920       SNPRINTF (buffer, sizeof(buffer),
921                 "(%s %c 0x%06x)",
922                 OP_SYMBOL (IC_LEFT (ic))->rname,
923                 val >= 0 ? '+' : '-',
924                 abs (val) & 0xffffff);
925   }
926   else
927   {
928       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
929       {
930           SNPRINTF(buffer, sizeof(buffer),
931                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
932       }
933       else
934       {
935           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
936       }
937   }
938
939   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
940   /* set immd2 field if required */
941   if (aop->aopu.aop_immd.from_cast_remat)
942   {
943       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
944       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
945   }
946
947   return aop;
948 }
949
950 /*-----------------------------------------------------------------*/
951 /* aopHasRegs - returns true if aop has regs between from-to       */
952 /*-----------------------------------------------------------------*/
953 static int aopHasRegs(asmop *aop, int from, int to)
954 {
955     int size =0;
956
957     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
958
959     for (; size < aop->size ; size++) {
960         int reg;
961         for (reg = from ; reg <= to ; reg++)
962             if (aop->aopu.aop_reg[size] == REG_WITH_INDEX(reg)) return 1;
963     }
964     return 0;
965 }
966
967 /*-----------------------------------------------------------------*/
968 /* regsInCommon - two operands have some registers in common       */
969 /*-----------------------------------------------------------------*/
970 static bool
971 regsInCommon (operand * op1, operand * op2)
972 {
973   symbol *sym1, *sym2;
974   int i;
975
976   /* if they have registers in common */
977   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
978     return FALSE;
979
980   sym1 = OP_SYMBOL (op1);
981   sym2 = OP_SYMBOL (op2);
982
983   if (sym1->nRegs == 0 || sym2->nRegs == 0)
984     return FALSE;
985
986   for (i = 0; i < sym1->nRegs; i++)
987     {
988       int j;
989       if (!sym1->regs[i])
990         continue;
991
992       for (j = 0; j < sym2->nRegs; j++)
993         {
994           if (!sym2->regs[j])
995             continue;
996
997           if (sym2->regs[j] == sym1->regs[i])
998             return TRUE;
999         }
1000     }
1001
1002   return FALSE;
1003 }
1004
1005 /*-----------------------------------------------------------------*/
1006 /* operandsEqu - equivalent                                        */
1007 /*-----------------------------------------------------------------*/
1008 static bool
1009 operandsEqu (operand * op1, operand * op2)
1010 {
1011   symbol *sym1, *sym2;
1012
1013   /* if they're not symbols */
1014   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1015     return FALSE;
1016
1017   sym1 = OP_SYMBOL (op1);
1018   sym2 = OP_SYMBOL (op2);
1019
1020   /* if both are itemps & one is spilt
1021      and the other is not then false */
1022   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
1023       sym1->isspilt != sym2->isspilt)
1024     return FALSE;
1025
1026   /* if they are the same */
1027   if (sym1 == sym2)
1028     return TRUE;
1029
1030   /* if they have the same rname */
1031   if (sym1->rname[0] && sym2->rname[0] &&
1032       strcmp (sym1->rname, sym2->rname) == 0 &&
1033       !(IS_PARM (op2) && IS_ITEMP (op1)))
1034     return TRUE;
1035
1036   /* if left is a tmp & right is not */
1037   if (IS_ITEMP (op1) &&
1038       !IS_ITEMP (op2) &&
1039       sym1->isspilt &&
1040       (sym1->usl.spillLoc == sym2))
1041     return TRUE;
1042
1043   if (IS_ITEMP (op2) &&
1044       !IS_ITEMP (op1) &&
1045       sym2->isspilt &&
1046       sym1->level > 0 &&
1047       (sym2->usl.spillLoc == sym1))
1048     return TRUE;
1049
1050   /* are they spilt to the same location */
1051   if (IS_ITEMP (op2) &&
1052       IS_ITEMP (op1) &&
1053       sym2->isspilt &&
1054       sym1->isspilt &&
1055       (sym1->usl.spillLoc == sym2->usl.spillLoc))
1056     return TRUE;
1057
1058   return FALSE;
1059 }
1060
1061 /*-----------------------------------------------------------------*/
1062 /* sameRegs - two asmops have the same registers                   */
1063 /*-----------------------------------------------------------------*/
1064 static bool
1065 sameRegs (asmop * aop1, asmop * aop2)
1066 {
1067   int i;
1068
1069   if (aop1 == aop2)
1070     {
1071       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
1072         {
1073           return FALSE;
1074         }
1075       return TRUE;
1076     }
1077
1078   if (aop1->type != AOP_REG && aop1->type != AOP_CRY)
1079     return FALSE;
1080
1081   if (aop1->type != aop2->type)
1082     return FALSE;
1083
1084   if (aop1->size != aop2->size)
1085     return FALSE;
1086
1087   for (i = 0; i < aop1->size; i++)
1088     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1089       return FALSE;
1090
1091   return TRUE;
1092 }
1093
1094 /*-----------------------------------------------------------------*/
1095 /* aopOp - allocates an asmop for an operand  :                    */
1096 /*-----------------------------------------------------------------*/
1097 static void
1098 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
1099 {
1100   asmop *aop;
1101   symbol *sym;
1102   int i;
1103
1104   if (!op)
1105     return;
1106
1107   /* if this a literal */
1108   if (IS_OP_LITERAL (op))
1109     {
1110       op->aop = aop = newAsmop (AOP_LIT);
1111       aop->aopu.aop_lit = op->operand.valOperand;
1112       aop->size = getSize (operandType (op));
1113       return;
1114     }
1115
1116   /* if already has a asmop then continue */
1117   if (op->aop)
1118     {
1119       if ((op->aop->type == AOP_DPTR && useDP2)
1120           || (op->aop->type == AOP_DPTR2 && !useDP2))
1121         op->aop = NULL;
1122       else
1123         {
1124           op->aop->allocated++;
1125           return;
1126         }
1127     }
1128
1129   /* if the underlying symbol has a aop */
1130   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1131     {
1132       op->aop = OP_SYMBOL (op)->aop;
1133       if ((op->aop->type == AOP_DPTR && useDP2)
1134           || (op->aop->type == AOP_DPTR2 && !useDP2))
1135         op->aop = NULL;
1136       else
1137         {
1138           op->aop->allocated++;
1139           return;
1140         }
1141     }
1142
1143   /* if this is a true symbol */
1144   if (IS_TRUE_SYMOP (op))
1145     {
1146       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
1147       return;
1148     }
1149
1150   /* this is a temporary : this has
1151      only five choices :
1152      a) register
1153      b) spillocation
1154      c) rematerialize
1155      d) conditional
1156      e) can be a return use only */
1157
1158   sym = OP_SYMBOL (op);
1159
1160   /* if the type is a conditional */
1161   if (sym->regType == REG_CND)
1162     {
1163       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1164       aop->size = 0;
1165       return;
1166     }
1167
1168   /* if it is spilt then two situations
1169      a) is rematerialize
1170      b) has a spill location */
1171   if (sym->isspilt || sym->nRegs == 0)
1172     {
1173
1174       /* rematerialize it NOW */
1175       if (sym->remat)
1176         {
1177           sym->aop = op->aop = aop =
1178             aopForRemat (sym);
1179           aop->size = getSize (sym->type);
1180           return;
1181         }
1182
1183       if (sym->accuse)
1184         {
1185           int i;
1186           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1187           aop->size = getSize (sym->type);
1188           for (i = 0; i < 2; i++)
1189             aop->aopu.aop_str[i] = accUse[i];
1190           return;
1191         }
1192
1193       if (sym->ruonly)
1194         {
1195           unsigned i;
1196
1197           if (useDP2)
1198             {
1199               /* a AOP_STR uses DPTR, but DPTR is already in use;
1200                * we're just hosed.
1201                */
1202                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1203             }
1204
1205           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1206           aop->size = getSize (sym->type);
1207           for (i = 0; i < fReturnSizeDS390; i++)
1208             aop->aopu.aop_str[i] = fReturn[i];
1209           return;
1210         }
1211
1212       if (sym->dptr) { /* has been allocated to a DPTRn */
1213           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1214           aop->size = getSize (sym->type);
1215           aop->aopu.dptr = sym->dptr;
1216           return ;
1217       }
1218
1219       if (sym->usl.spillLoc)
1220         {
1221           asmop *oldAsmOp = NULL;
1222
1223           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1224             {
1225               /* force a new aop if sizes differ */
1226               oldAsmOp = sym->usl.spillLoc->aop;
1227               sym->usl.spillLoc->aop = NULL;
1228             }
1229           sym->aop = op->aop = aop =
1230                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1231           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1232             {
1233               /* Don't reuse the new aop, go with the last one */
1234               sym->usl.spillLoc->aop = oldAsmOp;
1235             }
1236           aop->size = getSize (sym->type);
1237           return;
1238         }
1239
1240       /* else must be a dummy iTemp */
1241       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1242       aop->size = getSize (sym->type);
1243       return;
1244     }
1245
1246   /* if the type is a bit register */
1247   if (sym->regType == REG_BIT)
1248     {
1249       sym->aop = op->aop = aop = newAsmop (AOP_CRY);
1250       aop->size = sym->nRegs;//1???
1251       aop->aopu.aop_reg[0] = sym->regs[0];
1252       aop->aopu.aop_dir = sym->regs[0]->name;
1253       return;
1254     }
1255
1256   /* must be in a register */
1257   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1258   aop->size = sym->nRegs;
1259   for (i = 0; i < sym->nRegs; i++)
1260     aop->aopu.aop_reg[i] = sym->regs[i];
1261 }
1262
1263 /*-----------------------------------------------------------------*/
1264 /* freeAsmop - free up the asmop given to an operand               */
1265 /*----------------------------------------------------------------*/
1266 static void
1267 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1268 {
1269   asmop *aop;
1270
1271   if (!op)
1272     aop = aaop;
1273   else
1274     aop = op->aop;
1275
1276   if (!aop)
1277     return;
1278
1279   aop->allocated--;
1280
1281   if (aop->allocated)
1282     goto dealloc;
1283
1284   /* depending on the asmop type only three cases need work
1285      AOP_R0, AOP_R1 & AOP_STK */
1286   switch (aop->type)
1287     {
1288     case AOP_R0:
1289       if (_G.r0Pushed)
1290         {
1291           if (pop)
1292             {
1293               emitcode ("pop", "ar0");
1294               _G.r0Pushed--;
1295             }
1296         }
1297       bitVectUnSetBit (ic->rUsed, R0_IDX);
1298       break;
1299
1300     case AOP_R1:
1301       if (_G.r1Pushed)
1302         {
1303           if (pop)
1304             {
1305               emitcode ("pop", "ar1");
1306               _G.r1Pushed--;
1307             }
1308         }
1309       bitVectUnSetBit (ic->rUsed, R1_IDX);
1310       break;
1311
1312     case AOP_STK:
1313       {
1314         int sz = aop->size;
1315         int stk = aop->aopu.aop_stk + aop->size;
1316         bitVectUnSetBit (ic->rUsed, R0_IDX);
1317         bitVectUnSetBit (ic->rUsed, R1_IDX);
1318
1319         getFreePtr (ic, &aop, FALSE);
1320
1321         if (options.stack10bit)
1322           {
1323             /* I'm not sure what to do here yet... */
1324             /* #STUB */
1325             fprintf (stderr,
1326                      "*** Warning: probably generating bad code for "
1327                      "10 bit stack mode.\n");
1328           }
1329
1330         if (stk)
1331           {
1332             emitcode ("mov", "a,_bp");
1333             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1334             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1335           }
1336         else
1337           {
1338             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1339           }
1340
1341         while (sz--)
1342           {
1343             emitcode ("pop", "acc");
1344             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1345             if (!sz)
1346               break;
1347             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1348           }
1349         op->aop = aop;
1350         freeAsmop (op, NULL, ic, TRUE);
1351         if (_G.r1Pushed)
1352           {
1353             emitcode ("pop", "ar1");
1354             _G.r1Pushed--;
1355           }
1356         if (_G.r0Pushed)
1357           {
1358             emitcode ("pop", "ar0");
1359             _G.r0Pushed--;
1360           }
1361       }
1362     case AOP_DPTR2:
1363         if (_G.dptr1InUse) {
1364             emitcode ("pop","dpx1");
1365             emitcode ("pop","dph1");
1366             emitcode ("pop","dpl1");
1367         }
1368         break;
1369     case AOP_DPTR:
1370         if (_G.dptrInUse) {
1371             emitcode ("pop","dpx");
1372             emitcode ("pop","dph");
1373             emitcode ("pop","dpl");
1374         }
1375         break;
1376     }
1377
1378 dealloc:
1379   /* all other cases just dealloc */
1380   if (op)
1381     {
1382       op->aop = NULL;
1383       if (IS_SYMOP (op))
1384         {
1385           OP_SYMBOL (op)->aop = NULL;
1386           /* if the symbol has a spill */
1387           if (SPIL_LOC (op))
1388             SPIL_LOC (op)->aop = NULL;
1389         }
1390     }
1391 }
1392
1393 #define DEFAULT_ACC_WARNING 0
1394 static int saveAccWarn = DEFAULT_ACC_WARNING;
1395
1396
1397 /*-----------------------------------------------------------------*/
1398 /* aopGetUsesAcc - indicates ahead of time whether aopGet() will   */
1399 /*                 clobber the accumulator                         */
1400 /*-----------------------------------------------------------------*/
1401 static bool
1402 aopGetUsesAcc (operand * oper, int offset)
1403 {
1404   asmop * aop = AOP (oper);
1405
1406   if (offset > (aop->size - 1))
1407     return FALSE;
1408
1409   switch (aop->type)
1410     {
1411
1412     case AOP_R0:
1413     case AOP_R1:
1414       if (aop->paged)
1415         return TRUE;
1416       return FALSE;
1417     case AOP_DPTR:
1418     case AOP_DPTR2:
1419     case AOP_DPTRn:
1420       return TRUE;
1421     case AOP_IMMD:
1422       return FALSE;
1423     case AOP_DIR:
1424       return FALSE;
1425     case AOP_REG:
1426       wassert(strcmp(aop->aopu.aop_reg[offset]->name, "a"));
1427       return FALSE;
1428     case AOP_CRY:
1429       return TRUE;
1430     case AOP_ACC:
1431       if (offset)
1432         return FALSE;
1433       return TRUE;
1434     case AOP_LIT:
1435       return FALSE;
1436     case AOP_STR:
1437       if (strcmp (aop->aopu.aop_str[offset], "a") == 0)
1438         return TRUE;
1439       return FALSE;
1440     case AOP_DUMMY:
1441       return FALSE;
1442     default:
1443       /* Error case --- will have been caught already */
1444       wassert(0);
1445       return FALSE;
1446     }
1447 }
1448
1449 /*-------------------------------------------------------------------*/
1450 /* aopGet - for fetching value of the aop                            */
1451 /*                                                                   */
1452 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1453 /* in the accumulator. Set it to the name of a free register         */
1454 /* if acc must be preserved; the register will be used to preserve   */
1455 /* acc temporarily and to return the result byte.                    */
1456 /*-------------------------------------------------------------------*/
1457 static char *
1458 aopGet (operand * oper,
1459         int   offset,
1460         bool  bit16,
1461         bool  dname,
1462         char  *saveAcc)
1463 {
1464   asmop * aop = AOP (oper);
1465
1466   /* offset is greater than
1467      size then zero */
1468   if (offset > (aop->size - 1) &&
1469       aop->type != AOP_LIT)
1470     return zero;
1471
1472   /* depending on type */
1473   switch (aop->type)
1474     {
1475     case AOP_DUMMY:
1476       return zero;
1477
1478     case AOP_R0:
1479     case AOP_R1:
1480       /* if we need to increment it */
1481       while (offset > aop->coff)
1482         {
1483           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1484           aop->coff++;
1485         }
1486
1487       while (offset < aop->coff)
1488         {
1489           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1490           aop->coff--;
1491         }
1492
1493       aop->coff = offset;
1494       if (aop->paged)
1495         {
1496           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1497           return (dname ? "acc" : "a");
1498         }
1499       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1500       return Safe_strdup(buffer);
1501
1502     case AOP_DPTRn:
1503         assert(offset <= 3);
1504         return dptrn[aop->aopu.dptr][offset];
1505
1506     case AOP_DPTR:
1507     case AOP_DPTR2:
1508
1509       if (aop->type == AOP_DPTR2)
1510         {
1511           genSetDPTR (1);
1512         }
1513
1514       if (saveAcc)
1515         {
1516             TR_AP("#1");
1517 //          if (aop->type != AOP_DPTR2)
1518 //          {
1519 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1520 //              emitcode(";", "spanky: saveAcc for DPTR");
1521 //          }
1522
1523             emitcode ("xch", "a, %s", saveAcc);
1524         }
1525
1526       _flushLazyDPS ();
1527
1528       while (offset > aop->coff)
1529         {
1530           emitcode ("inc", "dptr");
1531           aop->coff++;
1532         }
1533
1534       while (offset < aop->coff)
1535         {
1536           emitcode ("lcall", "__decdptr");
1537           aop->coff--;
1538         }
1539
1540       aop->coff = offset;
1541       if (aop->code)
1542         {
1543           emitcode ("clr", "a");
1544           emitcode ("movc", "a,@a+dptr");
1545         }
1546       else
1547         {
1548           emitcode ("movx", "a,@dptr");
1549         }
1550
1551       if (aop->type == AOP_DPTR2)
1552         {
1553           genSetDPTR (0);
1554         }
1555
1556       if (saveAcc)
1557         {
1558           TR_AP("#2");
1559           emitcode ("xch", "a, %s", saveAcc);
1560 //        if (strcmp(saveAcc, "_ap"))
1561 //          {
1562 //            emitcode(";", "spiffy: non _ap return from aopGet.");
1563 //          }
1564
1565           return saveAcc;
1566         }
1567       return (dname ? "acc" : "a");
1568
1569     case AOP_IMMD:
1570       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1571         {
1572           SNPRINTF(buffer, sizeof(buffer),
1573                    "%s",aop->aopu.aop_immd.aop_immd2);
1574         }
1575       else if (bit16)
1576         {
1577           SNPRINTF(buffer, sizeof(buffer),
1578                    "#%s", aop->aopu.aop_immd.aop_immd1);
1579         }
1580       else if (offset)
1581         {
1582           switch (offset) {
1583           case 1:
1584               tsprintf(buffer, sizeof(buffer),
1585                        "#!his",aop->aopu.aop_immd.aop_immd1);
1586               break;
1587           case 2:
1588               tsprintf(buffer, sizeof(buffer),
1589                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1590               break;
1591           case 3:
1592               tsprintf(buffer, sizeof(buffer),
1593                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1594               break;
1595           default: /* should not need this (just in case) */
1596               SNPRINTF (buffer, sizeof(buffer),
1597                         "#(%s >> %d)",
1598                        aop->aopu.aop_immd.aop_immd1,
1599                        offset * 8);
1600           }
1601         }
1602       else
1603         {
1604           SNPRINTF (buffer, sizeof(buffer),
1605                     "#%s",
1606                     aop->aopu.aop_immd.aop_immd1);
1607         }
1608       return Safe_strdup(buffer);
1609
1610     case AOP_DIR:
1611       if (SPEC_SCLS (getSpec (operandType (oper))) == S_SFR && offset)
1612         {
1613           SNPRINTF (buffer, sizeof(buffer),
1614                     "(%s >> %d)",
1615                     aop->aopu.aop_dir, offset * 8);
1616         }
1617       else if (offset)
1618         {
1619           SNPRINTF (buffer, sizeof(buffer),
1620                     "(%s + %d)",
1621                    aop->aopu.aop_dir,
1622                    offset);
1623         }
1624       else
1625         {
1626           SNPRINTF (buffer, sizeof(buffer),
1627                     "%s",
1628                     aop->aopu.aop_dir);
1629         }
1630
1631       return Safe_strdup(buffer);
1632
1633     case AOP_REG:
1634       if (dname)
1635         return aop->aopu.aop_reg[offset]->dname;
1636       else
1637         return aop->aopu.aop_reg[offset]->name;
1638
1639     case AOP_CRY:
1640       emitcode ("clr", "a");
1641       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1642       emitcode ("rlc", "a");
1643       return (dname ? "acc" : "a");
1644
1645     case AOP_ACC:
1646       if (!offset && dname)
1647         return "acc";
1648       return aop->aopu.aop_str[offset];
1649
1650     case AOP_LIT:
1651       return aopLiteral (aop->aopu.aop_lit, offset);
1652
1653     case AOP_STR:
1654       aop->coff = offset;
1655       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1656           dname)
1657         return "acc";
1658
1659       return aop->aopu.aop_str[offset];
1660
1661     }
1662
1663   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1664           "aopget got unsupported aop->type");
1665   exit (1);
1666
1667   return NULL;  // not reached, but makes compiler happy.
1668 }
1669
1670 /*-----------------------------------------------------------------*/
1671 /* aopPut - puts a string for a aop and indicates if acc is in use */
1672 /*-----------------------------------------------------------------*/
1673 static bool
1674 aopPut (operand * result, const char *s, int offset)
1675 {
1676   bool bvolatile = isOperandVolatile (result, FALSE);
1677   bool accuse = FALSE;
1678   asmop * aop = AOP (result);
1679
1680   if (aop->size && offset > (aop->size - 1))
1681     {
1682       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1683               "aopPut got offset > aop->size");
1684       exit (1);
1685     }
1686
1687   /* will assign value to value */
1688   /* depending on where it is ofcourse */
1689   switch (aop->type)
1690     {
1691     case AOP_DUMMY:
1692       MOVA (s);         /* read s in case it was volatile */
1693       accuse = TRUE;
1694       break;
1695
1696     case AOP_DIR:
1697       if (SPEC_SCLS (getSpec (operandType (result))) == S_SFR && offset)
1698         {
1699           SNPRINTF (buffer, sizeof(buffer),
1700                     "(%s >> %d)",
1701                     aop->aopu.aop_dir, offset * 8);
1702         }
1703       else if (offset)
1704         {
1705           SNPRINTF (buffer, sizeof(buffer),
1706                     "(%s + %d)",
1707                     aop->aopu.aop_dir, offset);
1708         }
1709       else
1710         {
1711           SNPRINTF (buffer, sizeof(buffer),
1712                     "%s",
1713                     aop->aopu.aop_dir);
1714         }
1715
1716       if (strcmp (buffer, s) || bvolatile)
1717         {
1718           emitcode ("mov", "%s,%s", buffer, s);
1719         }
1720       if (!strcmp (buffer, "acc"))
1721         {
1722           accuse = TRUE;
1723         }
1724       break;
1725
1726     case AOP_REG:
1727       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1728           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1729         {
1730           if (*s == '@' ||
1731               strcmp (s, "r0") == 0 ||
1732               strcmp (s, "r1") == 0 ||
1733               strcmp (s, "r2") == 0 ||
1734               strcmp (s, "r3") == 0 ||
1735               strcmp (s, "r4") == 0 ||
1736               strcmp (s, "r5") == 0 ||
1737               strcmp (s, "r6") == 0 ||
1738               strcmp (s, "r7") == 0)
1739             {
1740               emitcode ("mov", "%s,%s",
1741                         aop->aopu.aop_reg[offset]->dname, s);
1742             }
1743             else
1744             {
1745               emitcode ("mov", "%s,%s",
1746                         aop->aopu.aop_reg[offset]->name, s);
1747             }
1748         }
1749       break;
1750
1751     case AOP_DPTRn:
1752         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1753         break;
1754
1755     case AOP_DPTR:
1756     case AOP_DPTR2:
1757
1758       if (aop->type == AOP_DPTR2)
1759         {
1760           genSetDPTR (1);
1761         }
1762       _flushLazyDPS ();
1763
1764       if (aop->code)
1765         {
1766           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1767                   "aopPut writing to code space");
1768           exit (1);
1769         }
1770
1771       while (offset > aop->coff)
1772         {
1773           aop->coff++;
1774           emitcode ("inc", "dptr");
1775         }
1776
1777       while (offset < aop->coff)
1778         {
1779           aop->coff--;
1780           emitcode ("lcall", "__decdptr");
1781         }
1782
1783       aop->coff = offset;
1784
1785       /* if not in accumulator */
1786       MOVA (s);
1787
1788       emitcode ("movx", "@dptr,a");
1789
1790       if (aop->type == AOP_DPTR2)
1791         {
1792           genSetDPTR (0);
1793         }
1794       break;
1795
1796     case AOP_R0:
1797     case AOP_R1:
1798       while (offset > aop->coff)
1799         {
1800           aop->coff++;
1801           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1802         }
1803       while (offset < aop->coff)
1804         {
1805           aop->coff--;
1806           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1807         }
1808       aop->coff = offset;
1809
1810       if (aop->paged)
1811         {
1812           MOVA (s);
1813           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1814         }
1815       else if (*s == '@')
1816         {
1817           MOVA (s);
1818           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1819         }
1820       else if (strcmp (s, "r0") == 0 ||
1821                strcmp (s, "r1") == 0 ||
1822                strcmp (s, "r2") == 0 ||
1823                strcmp (s, "r3") == 0 ||
1824                strcmp (s, "r4") == 0 ||
1825                strcmp (s, "r5") == 0 ||
1826                strcmp (s, "r6") == 0 ||
1827                strcmp (s, "r7") == 0)
1828         {
1829           char buffer[10];
1830           SNPRINTF (buffer, sizeof(buffer), "a%s", s);
1831           emitcode ("mov", "@%s,%s",
1832                     aop->aopu.aop_ptr->name, buffer);
1833         }
1834         else
1835         {
1836             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1837         }
1838       break;
1839
1840     case AOP_STK:
1841       if (strcmp (s, "a") == 0)
1842         emitcode ("push", "acc");
1843       else
1844         if (*s=='@') {
1845           MOVA(s);
1846           emitcode ("push", "acc");
1847         } else {
1848           emitcode ("push", s);
1849         }
1850
1851       break;
1852
1853     case AOP_CRY:
1854       /* if not bit variable */
1855       if (!aop->aopu.aop_dir)
1856         {
1857           /* inefficient: move carry into A and use jz/jnz */
1858           emitcode ("clr", "a");
1859           emitcode ("rlc", "a");
1860           accuse = TRUE;
1861         }
1862       else
1863         {
1864           if (s == zero)
1865             emitcode ("clr", "%s", aop->aopu.aop_dir);
1866           else if (s == one)
1867             emitcode ("setb", "%s", aop->aopu.aop_dir);
1868           else if (!strcmp (s, "c"))
1869             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1870           else if (strcmp (s, aop->aopu.aop_dir))
1871             {
1872               MOVA (s);
1873               /* set C, if a >= 1 */
1874               emitcode ("add", "a,#!constbyte",0xff);
1875               emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1876             }
1877         }
1878       break;
1879
1880     case AOP_STR:
1881       aop->coff = offset;
1882       if (strcmp (aop->aopu.aop_str[offset], s) || bvolatile)
1883         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1884       break;
1885
1886     case AOP_ACC:
1887       accuse = TRUE;
1888       aop->coff = offset;
1889       if (!offset && (strcmp (s, "acc") == 0) && !bvolatile)
1890         break;
1891
1892       if (strcmp (aop->aopu.aop_str[offset], s) && !bvolatile)
1893         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1894       break;
1895
1896     default:
1897       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1898               "aopPut got unsupported aop->type");
1899       exit (1);
1900     }
1901
1902     return accuse;
1903 }
1904
1905
1906 /*--------------------------------------------------------------------*/
1907 /* reAdjustPreg - points a register back to where it should (coff==0) */
1908 /*--------------------------------------------------------------------*/
1909 static void
1910 reAdjustPreg (asmop * aop)
1911 {
1912   if ((aop->coff==0) || (aop->size <= 1))
1913     return;
1914
1915   switch (aop->type)
1916     {
1917     case AOP_R0:
1918     case AOP_R1:
1919       while (aop->coff--)
1920         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1921       break;
1922     case AOP_DPTR:
1923     case AOP_DPTR2:
1924       if (aop->type == AOP_DPTR2)
1925         {
1926           genSetDPTR (1);
1927           _flushLazyDPS ();
1928         }
1929       while (aop->coff--)
1930         {
1931           emitcode ("lcall", "__decdptr");
1932         }
1933
1934       if (aop->type == AOP_DPTR2)
1935         {
1936           genSetDPTR (0);
1937         }
1938       break;
1939     }
1940   aop->coff = 0;
1941 }
1942
1943 /*-----------------------------------------------------------------*/
1944 /* opIsGptr: returns non-zero if the passed operand is       */
1945 /* a generic pointer type.             */
1946 /*-----------------------------------------------------------------*/
1947 static int
1948 opIsGptr (operand * op)
1949 {
1950   if (op && IS_GENPTR (operandType (op)) && (AOP_SIZE (op) == GPTRSIZE))
1951     {
1952       return 1;
1953     }
1954   return 0;
1955 }
1956
1957 /*-----------------------------------------------------------------*/
1958 /* getDataSize - get the operand data size                         */
1959 /*-----------------------------------------------------------------*/
1960 static int
1961 getDataSize (operand * op)
1962 {
1963   int size = AOP_SIZE (op);
1964
1965   if (size == GPTRSIZE)
1966     {
1967       sym_link *type = operandType (op);
1968       if (IS_GENPTR (type))
1969         {
1970           /* generic pointer; arithmetic operations
1971            * should ignore the high byte (pointer type).
1972            */
1973           size--;
1974         }
1975     }
1976   return size;
1977 }
1978
1979 /*-----------------------------------------------------------------*/
1980 /* outAcc - output Acc                                             */
1981 /*-----------------------------------------------------------------*/
1982 static void
1983 outAcc (operand * result)
1984 {
1985   int size, offset;
1986   size = getDataSize (result);
1987   if (size)
1988     {
1989       aopPut (result, "a", 0);
1990       size--;
1991       offset = 1;
1992       /* unsigned or positive */
1993       while (size--)
1994         {
1995           aopPut (result, zero, offset++);
1996         }
1997     }
1998 }
1999
2000 /*-----------------------------------------------------------------*/
2001 /* outBitC - output a bit C                                        */
2002 /*-----------------------------------------------------------------*/
2003 static void
2004 outBitC (operand * result)
2005 {
2006   /* if the result is bit */
2007   if (AOP_TYPE (result) == AOP_CRY)
2008     {
2009       aopPut (result, "c", 0);
2010     }
2011   else
2012     {
2013       emitcode ("clr", "a");
2014       emitcode ("rlc", "a");
2015       outAcc (result);
2016     }
2017 }
2018
2019 /*-----------------------------------------------------------------*/
2020 /* toBoolean - emit code for orl a,operator(sizeop)                */
2021 /*-----------------------------------------------------------------*/
2022 static void
2023 toBoolean (operand * oper)
2024 {
2025   int  size = AOP_SIZE (oper) - 1;
2026   int  offset = 1;
2027   bool pushedB;
2028
2029   /* The generic part of a generic pointer should
2030    * not participate in it's truth value.
2031    *
2032    * i.e. 0x10000000 is zero.
2033    */
2034   if (opIsGptr (oper))
2035     {
2036       D (emitcode (";", "toBoolean: generic ptr special case."));
2037       size--;
2038     }
2039
2040   _startLazyDPSEvaluation ();
2041   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2042   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2043     {
2044       pushedB = pushB ();
2045       emitcode("mov", "b,a");
2046       while (--size)
2047         {
2048           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2049           emitcode ("orl", "b,a");
2050         }
2051       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2052       emitcode ("orl", "a,b");
2053       popB (pushedB);
2054     }
2055   else
2056     {
2057       while (size--)
2058         {
2059           emitcode ("orl", "a,%s",
2060                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2061         }
2062     }
2063   _endLazyDPSEvaluation ();
2064 }
2065
2066
2067 /*-----------------------------------------------------------------*/
2068 /* genNot - generate code for ! operation                          */
2069 /*-----------------------------------------------------------------*/
2070 static void
2071 genNot (iCode * ic)
2072 {
2073   symbol *tlbl;
2074
2075   D (emitcode (";", "genNot"));
2076
2077   /* assign asmOps to operand & result */
2078   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2079   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2080
2081   /* if in bit space then a special case */
2082   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2083     {
2084       /* if left==result then cpl bit */
2085       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2086         {
2087           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2088         }
2089       else
2090         {
2091           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2092           emitcode ("cpl", "c");
2093           outBitC (IC_RESULT (ic));
2094         }
2095       goto release;
2096     }
2097
2098   toBoolean (IC_LEFT (ic));
2099
2100   /* set C, if a == 0 */
2101   tlbl = newiTempLabel (NULL);
2102   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2103   emitLabel (tlbl);
2104   outBitC (IC_RESULT (ic));
2105
2106 release:
2107   /* release the aops */
2108   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2109   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2110 }
2111
2112
2113 /*-----------------------------------------------------------------*/
2114 /* genCpl - generate code for complement                           */
2115 /*-----------------------------------------------------------------*/
2116 static void
2117 genCpl (iCode * ic)
2118 {
2119   int offset = 0;
2120   int size;
2121   symbol *tlbl;
2122   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2123
2124   D(emitcode (";", "genCpl"));
2125
2126   /* assign asmOps to operand & result */
2127   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2128   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2129
2130   /* special case if in bit space */
2131   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2132     {
2133       char *l;
2134
2135       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2136           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2137         {
2138           /* promotion rules are responsible for this strange result:
2139              bit -> int -> ~int -> bit
2140              uchar -> int -> ~int -> bit
2141           */
2142           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2143           goto release;
2144         }
2145
2146       tlbl=newiTempLabel(NULL);
2147       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2148       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2149           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2150           IS_AOP_PREG (IC_LEFT (ic)))
2151         {
2152           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2153         }
2154       else
2155         {
2156           MOVA (l);
2157           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2158         }
2159       emitLabel (tlbl);
2160       outBitC (IC_RESULT(ic));
2161       goto release;
2162     }
2163
2164   size = AOP_SIZE (IC_RESULT (ic));
2165   _startLazyDPSEvaluation ();
2166   while (size--)
2167     {
2168       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2169       MOVA (l);
2170       emitcode ("cpl", "a");
2171       aopPut (IC_RESULT (ic), "a", offset++);
2172     }
2173   _endLazyDPSEvaluation ();
2174
2175
2176 release:
2177   /* release the aops */
2178   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2179   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2180 }
2181
2182 /*-----------------------------------------------------------------*/
2183 /* genUminusFloat - unary minus for floating points                */
2184 /*-----------------------------------------------------------------*/
2185 static void
2186 genUminusFloat (operand * op, operand * result)
2187 {
2188   int size, offset = 0;
2189   char *l;
2190
2191   D (emitcode (";", "genUminusFloat"));
2192
2193   /* for this we just copy and then flip the bit */
2194
2195   _startLazyDPSEvaluation ();
2196   size = AOP_SIZE (op) - 1;
2197
2198   while (size--)
2199     {
2200       aopPut (result,
2201               aopGet (op, offset, FALSE, FALSE, NULL),
2202               offset);
2203       offset++;
2204     }
2205
2206   l = aopGet (op, offset, FALSE, FALSE, NULL);
2207   MOVA (l);
2208
2209   emitcode ("cpl", "acc.7");
2210   aopPut (result, "a", offset);
2211   _endLazyDPSEvaluation ();
2212 }
2213
2214 /*-----------------------------------------------------------------*/
2215 /* genUminus - unary minus code generation                         */
2216 /*-----------------------------------------------------------------*/
2217 static void
2218 genUminus (iCode * ic)
2219 {
2220   int offset, size;
2221   sym_link *optype;
2222
2223   D (emitcode (";", "genUminus"));
2224
2225   /* assign asmops */
2226   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2227   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2228
2229   /* if both in bit space then special
2230      case */
2231   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2232       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2233     {
2234
2235       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2236       emitcode ("cpl", "c");
2237       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2238       goto release;
2239     }
2240
2241   optype = operandType (IC_LEFT (ic));
2242
2243   /* if float then do float stuff */
2244   if (IS_FLOAT (optype))
2245     {
2246       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2247       goto release;
2248     }
2249
2250   /* otherwise subtract from zero */
2251   size = AOP_SIZE (IC_LEFT (ic));
2252   offset = 0;
2253   _startLazyDPSEvaluation ();
2254   while (size--)
2255     {
2256       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2257       if (!strcmp (l, "a"))
2258         {
2259           if (offset == 0)
2260             SETC;
2261           emitcode ("cpl", "a");
2262           emitcode ("addc", "a,#0");
2263         }
2264       else
2265         {
2266           if (offset == 0)
2267             CLRC;
2268           emitcode ("clr", "a");
2269           emitcode ("subb", "a,%s", l);
2270         }
2271       aopPut (IC_RESULT (ic), "a", offset++);
2272     }
2273   _endLazyDPSEvaluation ();
2274
2275   /* if any remaining bytes in the result */
2276   /* we just need to propagate the sign   */
2277   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2278     {
2279       emitcode ("rlc", "a");
2280       emitcode ("subb", "a,acc");
2281       while (size--)
2282         aopPut (IC_RESULT (ic), "a", offset++);
2283     }
2284
2285 release:
2286   /* release the aops */
2287   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2288   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2289 }
2290
2291 /*-----------------------------------------------------------------*/
2292 /* savermask - saves registers in the mask                         */
2293 /*-----------------------------------------------------------------*/
2294 static void savermask(bitVect *rs_mask)
2295 {
2296   int i;
2297
2298   if (options.useXstack)
2299     {
2300       if (bitVectBitValue (rs_mask, R0_IDX))
2301           emitcode ("mov", "b,r0");
2302       emitcode ("mov", "r0,%s", spname);
2303       for (i = 0; i < ds390_nRegs; i++)
2304         {
2305           if (bitVectBitValue (rs_mask, i))
2306             {
2307               if (i == R0_IDX)
2308                   emitcode ("mov", "a,b");
2309               else
2310                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2311               emitcode ("movx", "@r0,a");
2312               emitcode ("inc", "r0");
2313             }
2314         }
2315       emitcode ("mov", "%s,r0", spname);
2316       if (bitVectBitValue (rs_mask, R0_IDX))
2317           emitcode ("mov", "r0,b");
2318     }
2319   else
2320     {
2321       bool bits_pushed = FALSE;
2322       for (i = 0; i < ds390_nRegs; i++)
2323         {
2324           if (bitVectBitValue (rs_mask, i))
2325             {
2326               bits_pushed = pushReg (i, bits_pushed);
2327             }
2328         }
2329     }
2330 }
2331
2332 /*-----------------------------------------------------------------*/
2333 /* saveRegisters - will look for a call and save the registers     */
2334 /*-----------------------------------------------------------------*/
2335 static void
2336 saveRegisters (iCode * lic)
2337 {
2338   iCode *ic;
2339   bitVect *rsave;
2340
2341   /* look for call */
2342   for (ic = lic; ic; ic = ic->next)
2343     if (ic->op == CALL || ic->op == PCALL)
2344       break;
2345
2346   if (!ic)
2347     {
2348       fprintf (stderr, "found parameter push with no function call\n");
2349       return;
2350     }
2351
2352   /* if the registers have been saved already or don't need to be then
2353      do nothing */
2354   if (ic->regsSaved
2355       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2356     return;
2357
2358   /* special case if DPTR alive across a function call then must save it
2359      even though callee saves */
2360   if (IS_SYMOP(IC_LEFT(ic)) &&
2361       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2362     {
2363       int i;
2364       rsave = newBitVect(ic->rMask->size);
2365       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2366           if (bitVectBitValue(ic->rMask,i))
2367               rsave = bitVectSetBit(rsave,i);
2368       }
2369       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2370     }
2371   else
2372     {
2373       /* save the registers in use at this time but skip the
2374          ones for the result */
2375       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2376                              ds390_rUmaskForOp (IC_RESULT(ic)));
2377     }
2378   ic->regsSaved = 1;
2379   savermask(rsave);
2380 }
2381
2382 /*-----------------------------------------------------------------*/
2383 /* usavermask - restore registers with mask                        */
2384 /*-----------------------------------------------------------------*/
2385 static void unsavermask(bitVect *rs_mask)
2386 {
2387   int i;
2388
2389   if (options.useXstack)
2390     {
2391       emitcode ("mov", "r0,%s", spname);
2392       for (i = ds390_nRegs; i >= 0; i--)
2393         {
2394           if (bitVectBitValue (rs_mask, i))
2395             {
2396               regs * reg = REG_WITH_INDEX (i);
2397               emitcode ("dec", "r0");
2398               emitcode ("movx", "a,@r0");
2399               if (i == R0_IDX)
2400                 {
2401                   emitcode ("push", "acc");
2402                 }
2403               else
2404                 {
2405                   emitcode ("mov", "%s,a", reg->name);
2406                 }
2407             }
2408         }
2409       emitcode ("mov", "%s,r0", spname);
2410       if (bitVectBitValue (rs_mask, R0_IDX))
2411         {
2412           emitcode ("pop", "ar0");
2413         }
2414     }
2415   else
2416     {
2417       bool bits_popped = FALSE;
2418       for (i = ds390_nRegs; i >= 0; i--)
2419         {
2420           if (bitVectBitValue (rs_mask, i))
2421             {
2422               bits_popped = popReg (i, bits_popped);
2423             }
2424         }
2425     }
2426 }
2427
2428 /*-----------------------------------------------------------------*/
2429 /* unsaveRegisters - pop the pushed registers                      */
2430 /*-----------------------------------------------------------------*/
2431 static void
2432 unsaveRegisters (iCode * ic)
2433 {
2434   bitVect *rsave;
2435
2436   if (IS_SYMOP(IC_LEFT (ic)) &&
2437       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2438       int i;
2439       rsave = newBitVect(ic->rMask->size);
2440       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2441           if (bitVectBitValue(ic->rMask,i))
2442               rsave = bitVectSetBit(rsave,i);
2443       }
2444       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2445   } else {
2446     /* restore the registers in use at this time but skip the
2447        ones for the result */
2448     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2449                            ds390_rUmaskForOp (IC_RESULT(ic)));
2450   }
2451   unsavermask(rsave);
2452 }
2453
2454
2455 /*-----------------------------------------------------------------*/
2456 /* pushSide -                                                      */
2457 /*-----------------------------------------------------------------*/
2458 static void
2459 pushSide (operand * oper, int size, iCode * ic)
2460 {
2461   int offset = 0;
2462   int nPushed = _G.r0Pushed + _G.r1Pushed;
2463
2464   aopOp (oper, ic, FALSE, FALSE);
2465
2466   if (nPushed != _G.r0Pushed + _G.r1Pushed)
2467     {
2468       while (offset < size)
2469         {
2470           char *l = aopGet (oper, offset, FALSE, TRUE, NULL);
2471           emitcode ("mov", "%s,%s", fReturn[offset++], l);
2472         }
2473       freeAsmop (oper, NULL, ic, TRUE);
2474       offset = 0;
2475       while (offset < size)
2476         {
2477           emitcode ("push", "%s", fReturn[offset++]);
2478         }
2479       return;
2480     }
2481
2482   _startLazyDPSEvaluation ();
2483   while (size--)
2484     {
2485       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2486       if (AOP_TYPE (oper) != AOP_REG &&
2487           AOP_TYPE (oper) != AOP_DIR &&
2488           strcmp (l, "a"))
2489         {
2490           MOVA (l);
2491           emitcode ("push", "acc");
2492         }
2493       else
2494         {
2495           emitcode ("push", "%s", l);
2496         }
2497     }
2498   _endLazyDPSEvaluation ();
2499   freeAsmop (oper, NULL, ic, TRUE);
2500 }
2501
2502 /*-----------------------------------------------------------------*/
2503 /* assignResultValue - also indicates if acc is in use afterwards  */
2504 /*-----------------------------------------------------------------*/
2505 static bool
2506 assignResultValue (operand * oper, operand * func)
2507 {
2508   int offset = 0;
2509   unsigned size = AOP_SIZE (oper);
2510   bool accuse = FALSE;
2511   bool pushedA = FALSE;
2512
2513   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2514     {
2515       outBitC (oper);
2516       return FALSE;
2517     }
2518
2519   if (size == fReturnSizeDS390)
2520   {
2521       /* I don't think this case can ever happen... */
2522       /* ACC is the last part of this. If writing the result
2523        * uses ACC, we must preserve it.
2524        */
2525       if (AOP_NEEDSACC(oper))
2526       {
2527           emitcode(";", "assignResultValue special case for ACC.");
2528           emitcode("push", "acc");
2529           pushedA = TRUE;
2530           size--;
2531       }
2532   }
2533
2534   _startLazyDPSEvaluation ();
2535   while (size--)
2536     {
2537       accuse |= aopPut (oper, fReturn[offset], offset);
2538       offset++;
2539     }
2540   _endLazyDPSEvaluation ();
2541
2542   if (pushedA)
2543     {
2544         emitcode ("pop", "acc");
2545         accuse |= aopPut (oper, "a", offset);
2546     }
2547   return accuse;
2548 }
2549
2550
2551 /*-----------------------------------------------------------------*/
2552 /* genXpush - pushes onto the external stack                       */
2553 /*-----------------------------------------------------------------*/
2554 static void
2555 genXpush (iCode * ic)
2556 {
2557   asmop *aop = newAsmop (0);
2558   regs *r;
2559   int size, offset = 0;
2560
2561   D (emitcode (";", "genXpush"));
2562
2563   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2564   r = getFreePtr (ic, &aop, FALSE);
2565
2566   size = AOP_SIZE (IC_LEFT (ic));
2567
2568   if (size == 1)
2569     {
2570       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2571       emitcode ("mov", "%s,_spx", r->name);
2572       emitcode ("inc", "_spx"); // allocate space first
2573       emitcode ("movx", "@%s,a", r->name);
2574     }
2575   else
2576     {
2577       // allocate space first
2578       emitcode ("mov", "%s,_spx", r->name);
2579       MOVA (r->name);
2580       emitcode ("add", "a,#%d", size);
2581       emitcode ("mov", "_spx,a");
2582
2583       _startLazyDPSEvaluation ();
2584       while (size--)
2585         {
2586           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2587           emitcode ("movx", "@%s,a", r->name);
2588           emitcode ("inc", "%s", r->name);
2589         }
2590       _endLazyDPSEvaluation ();
2591     }
2592
2593   freeAsmop (NULL, aop, ic, TRUE);
2594   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2595 }
2596
2597 /*-----------------------------------------------------------------*/
2598 /* genIpush - generate code for pushing this gets a little complex  */
2599 /*-----------------------------------------------------------------*/
2600 static void
2601 genIpush (iCode * ic)
2602 {
2603   int size, offset = 0;
2604   char *l;
2605   char *prev = "";
2606
2607   D (emitcode (";", "genIpush"));
2608
2609   /* if this is not a parm push : ie. it is spill push
2610      and spill push is always done on the local stack */
2611   if (!ic->parmPush)
2612     {
2613
2614       /* and the item is spilt then do nothing */
2615       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2616         return;
2617
2618       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2619       size = AOP_SIZE (IC_LEFT (ic));
2620       /* push it on the stack */
2621       _startLazyDPSEvaluation ();
2622       while (size--)
2623         {
2624           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2625           if (*l == '#')
2626             {
2627               MOVA (l);
2628               l = "acc";
2629             }
2630           emitcode ("push", "%s", l);
2631         }
2632       _endLazyDPSEvaluation ();
2633       return;
2634     }
2635
2636   /* this is a parameter push: in this case we call
2637      the routine to find the call and save those
2638      registers that need to be saved */
2639   saveRegisters (ic);
2640
2641   /* if use external stack then call the external
2642      stack pushing routine */
2643   if (options.useXstack)
2644     {
2645       genXpush (ic);
2646       return;
2647     }
2648
2649   /* then do the push */
2650   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2651
2652   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2653   size = AOP_SIZE (IC_LEFT (ic));
2654
2655   _startLazyDPSEvaluation ();
2656   while (size--)
2657     {
2658       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2659       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2660           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2661           strcmp (l, "acc"))
2662         {
2663           if (strcmp (l, prev) || *l == '@')
2664             MOVA (l);
2665           emitcode ("push", "acc");
2666         }
2667       else
2668         {
2669             emitcode ("push", "%s", l);
2670         }
2671       prev = l;
2672     }
2673   _endLazyDPSEvaluation ();
2674
2675   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2676 }
2677
2678 /*-----------------------------------------------------------------*/
2679 /* genIpop - recover the registers: can happen only for spilling   */
2680 /*-----------------------------------------------------------------*/
2681 static void
2682 genIpop (iCode * ic)
2683 {
2684   int size, offset;
2685
2686   D (emitcode (";", "genIpop"));
2687
2688   /* if the temp was not pushed then */
2689   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2690     return;
2691
2692   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2693   size = AOP_SIZE (IC_LEFT (ic));
2694   offset = (size - 1);
2695   _startLazyDPSEvaluation ();
2696   while (size--)
2697     {
2698       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2699                                      FALSE, TRUE, NULL));
2700     }
2701   _endLazyDPSEvaluation ();
2702
2703   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2704 }
2705
2706 /*-----------------------------------------------------------------*/
2707 /* saveRBank - saves an entire register bank on the stack          */
2708 /*-----------------------------------------------------------------*/
2709 static void
2710 saveRBank (int bank, iCode * ic, bool pushPsw)
2711 {
2712   int i;
2713   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2714   asmop *aop = NULL;
2715   regs *r = NULL;
2716
2717   if (options.useXstack)
2718     {
2719       if (!ic)
2720         {
2721           /* Assume r0 is available for use. */
2722           r = REG_WITH_INDEX (R0_IDX);;
2723         }
2724       else
2725         {
2726           aop = newAsmop (0);
2727           r = getFreePtr (ic, &aop, FALSE);
2728         }
2729       // allocate space first
2730       emitcode ("mov", "%s,_spx", r->name);
2731       MOVA (r->name);
2732       emitcode ("add", "a,#%d", count);
2733       emitcode ("mov", "_spx,a");
2734     }
2735
2736   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2737     {
2738       if (options.useXstack)
2739         {
2740           emitcode ("mov", "a,(%s+%d)",
2741                     regs390[i].base, 8 * bank + regs390[i].offset);
2742           emitcode ("movx", "@%s,a", r->name);
2743           if (--count)
2744             emitcode ("inc", "%s", r->name);
2745         }
2746       else
2747         emitcode ("push", "(%s+%d)",
2748                   regs390[i].base, 8 * bank + regs390[i].offset);
2749     }
2750
2751   if (ds390_nBitRegs > 0)
2752     {
2753       if (options.useXstack)
2754         {
2755           emitcode ("mov", "a,bits");
2756           emitcode ("movx", "@%s,a", r->name);
2757           if (--count)
2758             emitcode ("inc", "%s", r->name);
2759         }
2760       else
2761         {
2762           emitcode ("push", "bits");
2763         }
2764       BitBankUsed = 1;
2765     }
2766
2767   if (pushPsw)
2768     {
2769       if (options.useXstack)
2770         {
2771           emitcode ("mov", "a,psw");
2772           emitcode ("movx", "@%s,a", r->name);
2773         }
2774       else
2775       {
2776         emitcode ("push", "psw");
2777       }
2778
2779       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2780     }
2781
2782   if (aop)
2783     {
2784       freeAsmop (NULL, aop, ic, TRUE);
2785     }
2786
2787   if (ic)
2788   {
2789     ic->bankSaved = 1;
2790   }
2791 }
2792
2793 /*-----------------------------------------------------------------*/
2794 /* unsaveRBank - restores the register bank from stack             */
2795 /*-----------------------------------------------------------------*/
2796 static void
2797 unsaveRBank (int bank, iCode * ic, bool popPsw)
2798 {
2799   int i;
2800   asmop *aop = NULL;
2801   regs *r = NULL;
2802
2803   if (options.useXstack)
2804     {
2805       if (!ic)
2806         {
2807           /* Assume r0 is available for use. */
2808           r = REG_WITH_INDEX (R0_IDX);;
2809         }
2810       else
2811         {
2812           aop = newAsmop (0);
2813           r = getFreePtr (ic, &aop, FALSE);
2814         }
2815       emitcode ("mov", "%s,_spx", r->name);
2816     }
2817
2818   if (popPsw)
2819     {
2820       if (options.useXstack)
2821         {
2822           emitcode ("dec", "%s", r->name);
2823           emitcode ("movx", "a,@%s", r->name);
2824           emitcode ("mov", "psw,a");
2825         }
2826       else
2827       {
2828         emitcode ("pop", "psw");
2829       }
2830     }
2831
2832   if (ds390_nBitRegs > 0)
2833     {
2834       if (options.useXstack)
2835         {
2836           emitcode ("dec", "%s", r->name);
2837           emitcode ("movx", "a,@%s", r->name);
2838           emitcode ("mov", "bits,a");
2839         }
2840       else
2841         {
2842           emitcode ("pop", "bits");
2843         }
2844     }
2845
2846   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2847     {
2848       if (options.useXstack)
2849         {
2850           emitcode ("dec", "%s", r->name);
2851           emitcode ("movx", "a,@%s", r->name);
2852           emitcode ("mov", "(%s+%d),a",
2853                     regs390[i].base, 8 * bank + regs390[i].offset);
2854         }
2855       else
2856         {
2857           emitcode ("pop", "(%s+%d)",
2858                     regs390[i].base, 8 * bank + regs390[i].offset);
2859         }
2860     }
2861
2862   if (options.useXstack)
2863     {
2864       emitcode ("mov", "_spx,%s", r->name);
2865     }
2866
2867   if (aop)
2868     {
2869       freeAsmop (NULL, aop, ic, TRUE);
2870     }
2871 }
2872
2873 /*-----------------------------------------------------------------*/
2874 /* genSend - gen code for SEND                                     */
2875 /*-----------------------------------------------------------------*/
2876 static void genSend(set *sendSet)
2877 {
2878   iCode *sic;
2879   int bit_count = 0;
2880   int sendCount = 0 ;
2881   static int rb1_count = 0;
2882
2883   /* first we do all bit parameters */
2884   for (sic = setFirstItem (sendSet); sic;
2885        sic = setNextItem (sendSet))
2886     {
2887       if (sic->argreg > 12)
2888         {
2889           int bit = sic->argreg-13;
2890
2891           aopOp (IC_LEFT (sic), sic, FALSE,
2892                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2893
2894           /* if left is a literal then
2895              we know what the value is */
2896           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2897             {
2898               if (((int) operandLitValue (IC_LEFT (sic))))
2899                   emitcode ("setb", "b[%d]", bit);
2900               else
2901                   emitcode ("clr", "b[%d]", bit);
2902             }
2903           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2904             {
2905               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2906                 if (strcmp (l, "c"))
2907                     emitcode ("mov", "c,%s", l);
2908                 emitcode ("mov", "b[%d],c", bit);
2909             }
2910           else
2911             {
2912               /* we need to or */
2913               toBoolean (IC_LEFT (sic));
2914               /* set C, if a >= 1 */
2915               emitcode ("add", "a,#0xff");
2916               emitcode ("mov", "b[%d],c", bit);
2917             }
2918           bit_count++;
2919           BitBankUsed = 1;
2920
2921           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2922         }
2923     }
2924
2925   if (bit_count)
2926     {
2927       saveRegisters (setFirstItem (sendSet));
2928       emitcode ("mov", "bits,b");
2929     }
2930
2931   /* then we do all other parameters */
2932   for (sic = setFirstItem (sendSet); sic;
2933        sic = setNextItem (sendSet))
2934     {
2935       if (sic->argreg <= 12)
2936       {
2937         int size, offset = 0;
2938
2939         size = getSize (operandType (IC_LEFT (sic)));
2940         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2941         if (sendCount == 0) { /* first parameter */
2942             // we know that dpl(hxb) is the result, so
2943             rb1_count = 0 ;
2944             _startLazyDPSEvaluation ();
2945             if (size>1) {
2946                 aopOp (IC_LEFT (sic), sic, FALSE,
2947                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2948             } else {
2949                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2950             }
2951             while (size--)
2952               {
2953                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2954                 if (strcmp (l, fReturn[offset]))
2955                   {
2956                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2957                   }
2958                 offset++;
2959               }
2960             _endLazyDPSEvaluation ();
2961             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2962             rb1_count =0;
2963         } else { /* if more parameter in registers */
2964             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2965             while (size--) {
2966                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2967                                                                 FALSE, FALSE, NULL));
2968             }
2969             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2970         }
2971         sendCount++;
2972       }
2973     }
2974 }
2975
2976 static void
2977 adjustEsp(const char *reg)
2978 {
2979     emitcode ("anl","%s,#3", reg);
2980     if (TARGET_IS_DS400)
2981     {
2982         emitcode ("orl","%s,#!constbyte",
2983                   reg,
2984                   (options.stack_loc >> 8) & 0xff);
2985     }
2986 }
2987
2988 /*-----------------------------------------------------------------*/
2989 /* selectRegBank - emit code to select the register bank           */
2990 /*-----------------------------------------------------------------*/
2991 static void
2992 selectRegBank (short bank, bool keepFlags)
2993 {
2994   /* if f.e. result is in carry */
2995   if (keepFlags)
2996     {
2997       emitcode ("anl", "psw,#0xE7");
2998       if (bank)
2999         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
3000     }
3001   else
3002     {
3003       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
3004     }
3005 }
3006
3007 /*-----------------------------------------------------------------*/
3008 /* genCall - generates a call statement                            */
3009 /*-----------------------------------------------------------------*/
3010 static void
3011 genCall (iCode * ic)
3012 {
3013   sym_link *dtype;
3014   sym_link *etype;
3015   bool restoreBank = FALSE;
3016   bool swapBanks = FALSE;
3017   bool accuse = FALSE;
3018   bool accPushed = FALSE;
3019   bool resultInF0 = FALSE;
3020   bool assignResultGenerated = FALSE;
3021
3022   D (emitcode (";", "genCall"));
3023
3024   /* if we are calling a not _naked function that is not using
3025      the same register bank then we need to save the
3026      destination registers on the stack */
3027   dtype = operandType (IC_LEFT (ic));
3028   etype = getSpec(dtype);
3029   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3030       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3031       IFFUNC_ISISR (currFunc->type))
3032   {
3033       if (!ic->bankSaved)
3034       {
3035            /* This is unexpected; the bank should have been saved in
3036             * genFunction.
3037             */
3038            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3039            restoreBank = TRUE;
3040       }
3041       swapBanks = TRUE;
3042   }
3043
3044   /* if caller saves & we have not saved then */
3045   if (!ic->regsSaved)
3046       saveRegisters (ic);
3047
3048   /* if send set is not empty then assign */
3049   /* We've saved all the registers we care about;
3050   * therefore, we may clobber any register not used
3051   * in the calling convention (i.e. anything not in
3052   * fReturn.
3053   */
3054   if (_G.sendSet)
3055     {
3056         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3057             genSend(reverseSet(_G.sendSet));
3058         } else {
3059             genSend(_G.sendSet);
3060         }
3061       _G.sendSet = NULL;
3062     }
3063
3064   if (swapBanks)
3065     {
3066       emitcode ("mov", "psw,#!constbyte",
3067          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3068     }
3069
3070   /* make the call */
3071   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3072                             OP_SYMBOL (IC_LEFT (ic))->rname :
3073                             OP_SYMBOL (IC_LEFT (ic))->name));
3074
3075   if (swapBanks)
3076     {
3077       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3078     }
3079
3080   /* if we need assign a result value */
3081   if ((IS_ITEMP (IC_RESULT (ic)) &&
3082        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3083        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3084         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3085         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3086       IS_TRUE_SYMOP (IC_RESULT (ic)))
3087     {
3088       if (isOperandInFarSpace (IC_RESULT (ic))
3089           && getSize (operandType (IC_RESULT (ic))) <= 2)
3090         {
3091           int size = getSize (operandType (IC_RESULT (ic)));
3092           bool pushedB = FALSE;
3093
3094           /* Special case for 1 or 2 byte return in far space. */
3095           MOVA (fReturn[0]);
3096           if (size > 1)
3097             {
3098               pushedB = pushB ();
3099               emitcode ("mov", "b,%s", fReturn[1]);
3100             }
3101
3102           _G.accInUse++;
3103           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3104           _G.accInUse--;
3105
3106           popB (pushedB);
3107
3108           aopPut (IC_RESULT (ic), "a", 0);
3109
3110           if (size > 1)
3111             {
3112               aopPut (IC_RESULT (ic), "b", 1);
3113             }
3114           assignResultGenerated = TRUE;
3115           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3116         }
3117       else
3118         {
3119           bool pushedB = pushB ();
3120           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3121           popB (pushedB);
3122
3123           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3124           assignResultGenerated = TRUE;
3125           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3126         }
3127     }
3128
3129   /* adjust the stack for parameters if required */
3130   if (ic->parmBytes)
3131     {
3132       int i;
3133       if (options.stack10bit) {
3134           if (ic->parmBytes <= 10) {
3135               emitcode(";","stack adjustment for parms");
3136               for (i=0; i < ic->parmBytes ; i++) {
3137                   emitcode("pop","acc");
3138               }
3139           } else {
3140               PROTECT_SP;
3141               emitcode ("clr","c");
3142               emitcode ("mov","a,sp");
3143               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3144               emitcode ("mov","sp,a");
3145               emitcode ("mov","a,esp");
3146               adjustEsp("a");
3147               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3148               emitcode ("mov","esp,a");
3149               UNPROTECT_SP;
3150           }
3151       } else {
3152           if (ic->parmBytes > 3)
3153             {
3154               if (accuse)
3155                 {
3156                   emitcode ("push", "acc");
3157                   accPushed = TRUE;
3158                 }
3159               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3160                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3161                   !assignResultGenerated)
3162                 {
3163                   emitcode ("mov", "F0,c");
3164                   resultInF0 = TRUE;
3165                 }
3166
3167               emitcode ("mov", "a,%s", spname);
3168               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3169               emitcode ("mov", "%s,a", spname);
3170
3171               /* unsaveRegisters from xstack needs acc, but */
3172               /* unsaveRegisters from stack needs this popped */
3173               if (accPushed && !options.useXstack)
3174                 {
3175                   emitcode ("pop", "acc");
3176                   accPushed = FALSE;
3177                 }
3178             }
3179           else
3180               for (i = 0; i < ic->parmBytes; i++)
3181                   emitcode ("dec", "%s", spname);
3182       }
3183   }
3184
3185   /* if we had saved some registers then unsave them */
3186   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3187     {
3188       if (accuse && !accPushed && options.useXstack)
3189         {
3190           /* xstack needs acc, but doesn't touch normal stack */
3191           emitcode ("push", "acc");
3192           accPushed = TRUE;
3193         }
3194       unsaveRegisters (ic);
3195     }
3196
3197   /* if register bank was saved then pop them */
3198   if (restoreBank)
3199     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3200
3201   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3202     {
3203       if (resultInF0)
3204           emitcode ("mov", "c,F0");
3205
3206       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3207       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3208       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3209     }
3210
3211   if (accPushed)
3212     emitcode ("pop", "acc");
3213 }
3214
3215 /*-----------------------------------------------------------------*/
3216 /* genPcall - generates a call by pointer statement                */
3217 /*-----------------------------------------------------------------*/
3218 static void
3219 genPcall (iCode * ic)
3220 {
3221   sym_link *dtype;
3222   sym_link *etype;
3223   symbol *rlbl = newiTempLabel (NULL);
3224   bool restoreBank=FALSE;
3225   bool resultInF0 = FALSE;
3226
3227   D (emitcode (";", "genPcall"));
3228
3229   dtype = operandType (IC_LEFT (ic))->next;
3230   etype = getSpec(dtype);
3231   /* if caller saves & we have not saved then */
3232   if (!ic->regsSaved)
3233     saveRegisters (ic);
3234
3235   /* if we are calling a not _naked function that is not using
3236      the same register bank then we need to save the
3237      destination registers on the stack */
3238   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3239       IFFUNC_ISISR (currFunc->type) &&
3240       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3241     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3242     restoreBank=TRUE;
3243   }
3244
3245   /* push the return address on to the stack */
3246   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3247   emitcode ("push", "acc");
3248   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3249   emitcode ("push", "acc");
3250
3251   if (options.model == MODEL_FLAT24)
3252     {
3253       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3254       emitcode ("push", "acc");
3255     }
3256
3257   /* now push the function address */
3258   pushSide (IC_LEFT (ic), FPTRSIZE, ic);
3259
3260   /* if send set is not empty then assign */
3261   if (_G.sendSet)
3262     {
3263         genSend(reverseSet(_G.sendSet));
3264         _G.sendSet = NULL;
3265     }
3266
3267   /* make the call */
3268   emitcode ("ret", "");
3269   emitLabel (rlbl);
3270
3271
3272   /* if we need assign a result value */
3273   if ((IS_ITEMP (IC_RESULT (ic)) &&
3274        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3275        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3276         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3277       IS_TRUE_SYMOP (IC_RESULT (ic)))
3278     {
3279
3280       _G.accInUse++;
3281       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3282       _G.accInUse--;
3283
3284       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3285
3286       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3287     }
3288
3289   /* adjust the stack for parameters if required */
3290   if (ic->parmBytes)
3291     {
3292       int i;
3293       if (options.stack10bit) {
3294           if (ic->parmBytes <= 10) {
3295               emitcode(";","stack adjustment for parms");
3296               for (i=0; i < ic->parmBytes ; i++) {
3297                   emitcode("pop","acc");
3298               }
3299           } else {
3300               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3301                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3302                 {
3303                   emitcode ("mov", "F0,c");
3304                   resultInF0 = TRUE;
3305                 }
3306
3307               PROTECT_SP;
3308               emitcode ("clr","c");
3309               emitcode ("mov","a,sp");
3310               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3311               emitcode ("mov","sp,a");
3312               emitcode ("mov","a,esp");
3313               adjustEsp("a");
3314               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3315               emitcode ("mov","esp,a");
3316               UNPROTECT_SP;
3317           }
3318       } else {
3319           if (ic->parmBytes > 3) {
3320               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3321                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3322                 {
3323                   emitcode ("mov", "F0,c");
3324                   resultInF0 = TRUE;
3325                 }
3326
3327               emitcode ("mov", "a,%s", spname);
3328               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3329               emitcode ("mov", "%s,a", spname);
3330           }
3331           else
3332               for (i = 0; i < ic->parmBytes; i++)
3333                   emitcode ("dec", "%s", spname);
3334       }
3335     }
3336   /* if register bank was saved then unsave them */
3337   if (restoreBank)
3338     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3339
3340   /* if we had saved some registers then unsave them */
3341   if (ic->regsSaved)
3342     unsaveRegisters (ic);
3343
3344   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3345     {
3346       if (resultInF0)
3347           emitcode ("mov", "c,F0");
3348
3349       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3350       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3351       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3352     }
3353 }
3354
3355 /*-----------------------------------------------------------------*/
3356 /* resultRemat - result  is rematerializable                       */
3357 /*-----------------------------------------------------------------*/
3358 static int
3359 resultRemat (iCode * ic)
3360 {
3361   if (SKIP_IC (ic) || ic->op == IFX)
3362     return 0;
3363
3364   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3365     {
3366       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3367       if (sym->remat && !POINTER_SET (ic))
3368         return 1;
3369     }
3370
3371   return 0;
3372 }
3373
3374 /*-----------------------------------------------------------------*/
3375 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3376 /*-----------------------------------------------------------------*/
3377 static int
3378 regsCmp(void *p1, void *p2)
3379 {
3380   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3381 }
3382
3383 static bool
3384 inExcludeList (char *s)
3385 {
3386   const char *p = setFirstItem(options.excludeRegsSet);
3387
3388   if (p == NULL || STRCASECMP(p, "none") == 0)
3389     return FALSE;
3390
3391
3392   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3393 }
3394
3395 /*-----------------------------------------------------------------*/
3396 /* genFunction - generated code for function entry                 */
3397 /*-----------------------------------------------------------------*/
3398 static void
3399 genFunction (iCode * ic)
3400 {
3401   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3402   sym_link *ftype;
3403   bool     switchedPSW = FALSE;
3404   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3405
3406   D (emitcode (";", "genFunction"));
3407
3408   _G.nRegsSaved = 0;
3409   /* create the function header */
3410   emitcode (";", "-----------------------------------------");
3411   emitcode (";", " function %s", sym->name);
3412   emitcode (";", "-----------------------------------------");
3413
3414   emitcode ("", "%s:", sym->rname);
3415   lineCurr->isLabel = 1;
3416   ftype = operandType (IC_LEFT (ic));
3417   _G.currentFunc = sym;
3418
3419   if (IFFUNC_ISNAKED(ftype))
3420   {
3421       emitcode(";", "naked function: no prologue.");
3422       return;
3423   }
3424
3425   if (options.stack_probe)
3426       emitcode ("lcall","__stack_probe");
3427
3428   /* here we need to generate the equates for the
3429      register bank if required */
3430   if (FUNC_REGBANK (ftype) != rbank)
3431     {
3432       int i;
3433
3434       rbank = FUNC_REGBANK (ftype);
3435       for (i = 0; i < ds390_nRegs; i++)
3436         {
3437           if (regs390[i].print) {
3438               if (strcmp (regs390[i].base, "0") == 0)
3439                   emitcode ("", "%s !equ !constbyte",
3440                             regs390[i].dname,
3441                             8 * rbank + regs390[i].offset);
3442               else
3443                   emitcode ("", "%s !equ %s + !constbyte",
3444                             regs390[i].dname,
3445                             regs390[i].base,
3446                             8 * rbank + regs390[i].offset);
3447           }
3448         }
3449     }
3450
3451   /* if this is an interrupt service routine then
3452      save acc, b, dpl, dph  */
3453   if (IFFUNC_ISISR (sym->type))
3454       { /* is ISR */
3455       if (!inExcludeList ("acc"))
3456         emitcode ("push", "acc");
3457       if (!inExcludeList ("b"))
3458         emitcode ("push", "b");
3459       if (!inExcludeList ("dpl"))
3460         emitcode ("push", "dpl");
3461       if (!inExcludeList ("dph"))
3462         emitcode ("push", "dph");
3463       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3464         {
3465           emitcode ("push", "dpx");
3466           /* Make sure we're using standard DPTR */
3467           emitcode ("push", "dps");
3468           emitcode ("mov", "dps,#0");
3469           if (options.stack10bit)
3470             {
3471               /* This ISR could conceivably use DPTR2. Better save it. */
3472               emitcode ("push", "dpl1");
3473               emitcode ("push", "dph1");
3474               emitcode ("push", "dpx1");
3475               emitcode ("push",  DP2_RESULT_REG);
3476             }
3477         }
3478       /* if this isr has no bank i.e. is going to
3479          run with bank 0 , then we need to save more
3480          registers :-) */
3481       if (!FUNC_REGBANK (sym->type))
3482         {
3483             int i;
3484
3485           /* if this function does not call any other
3486              function then we can be economical and
3487              save only those registers that are used */
3488           if (!IFFUNC_HASFCALL(sym->type))
3489             {
3490               /* if any registers used */
3491               if (sym->regsUsed)
3492                 {
3493                   bool bits_pushed = FALSE;
3494                   /* save the registers used */
3495                   for (i = 0; i < sym->regsUsed->size; i++)
3496                     {
3497                       if (bitVectBitValue (sym->regsUsed, i))
3498                         bits_pushed = pushReg (i, bits_pushed);
3499                     }
3500                 }
3501             }
3502           else
3503             {
3504               /* this function has a function call. We cannot
3505                  determine register usage so we will have to push the
3506                  entire bank */
3507               saveRBank (0, ic, FALSE);
3508               if (options.parms_in_bank1) {
3509                   for (i=0; i < 8 ; i++ ) {
3510                       emitcode ("push","%s",rb1regs[i]);
3511                   }
3512               }
3513             }
3514         }
3515         else
3516         {
3517             /* This ISR uses a non-zero bank.
3518              *
3519              * We assume that the bank is available for our
3520              * exclusive use.
3521              *
3522              * However, if this ISR calls a function which uses some
3523              * other bank, we must save that bank entirely.
3524              */
3525             unsigned long banksToSave = 0;
3526
3527             if (IFFUNC_HASFCALL(sym->type))
3528             {
3529
3530 #define MAX_REGISTER_BANKS 4
3531
3532                 iCode *i;
3533                 int ix;
3534
3535                 for (i = ic; i; i = i->next)
3536                 {
3537                     if (i->op == ENDFUNCTION)
3538                     {
3539                         /* we got to the end OK. */
3540                         break;
3541                     }
3542
3543                     if (i->op == CALL)
3544                     {
3545                         sym_link *dtype;
3546
3547                         dtype = operandType (IC_LEFT(i));
3548                         if (dtype
3549                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3550                         {
3551                              /* Mark this bank for saving. */
3552                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3553                              {
3554                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3555                              }
3556                              else
3557                              {
3558                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3559                              }
3560
3561                              /* And note that we don't need to do it in
3562                               * genCall.
3563                               */
3564                              i->bankSaved = 1;
3565                         }
3566                     }
3567                     if (i->op == PCALL)
3568                     {
3569                         /* This is a mess; we have no idea what
3570                          * register bank the called function might
3571                          * use.
3572                          *
3573                          * The only thing I can think of to do is
3574                          * throw a warning and hope.
3575                          */
3576                         werror(W_FUNCPTR_IN_USING_ISR);
3577                     }
3578                 }
3579
3580                 if (banksToSave && options.useXstack)
3581                 {
3582                     /* Since we aren't passing it an ic,
3583                      * saveRBank will assume r0 is available to abuse.
3584                      *
3585                      * So switch to our (trashable) bank now, so
3586                      * the caller's R0 isn't trashed.
3587                      */
3588                     emitcode ("push", "psw");
3589                     emitcode ("mov", "psw,#!constbyte",
3590                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3591                     switchedPSW = TRUE;
3592                 }
3593
3594                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3595                 {
3596                      if (banksToSave & (1 << ix))
3597                      {
3598                          saveRBank(ix, NULL, FALSE);
3599                      }
3600                 }
3601             }
3602             // TODO: this needs a closer look
3603             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3604         }
3605     }
3606   else
3607     {
3608       /* if callee-save to be used for this function
3609          then save the registers being used in this function */
3610       if (IFFUNC_CALLEESAVES(sym->type))
3611         {
3612           int i;
3613
3614           /* if any registers used */
3615           if (sym->regsUsed)
3616             {
3617               bool bits_pushed = FALSE;
3618               /* save the registers used */
3619               for (i = 0; i < sym->regsUsed->size; i++)
3620                 {
3621                   if (bitVectBitValue (sym->regsUsed, i))
3622                     {
3623                       bits_pushed = pushReg (i, bits_pushed);
3624                       _G.nRegsSaved++;
3625                     }
3626                 }
3627             }
3628         }
3629     }
3630
3631   /* set the register bank to the desired value */
3632   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3633    && !switchedPSW)
3634     {
3635       emitcode ("push", "psw");
3636       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3637     }
3638
3639   if (fReentrant &&
3640        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3641       if (options.stack10bit) {
3642           emitcode ("push","_bpx");
3643           emitcode ("push","_bpx+1");
3644           emitcode ("mov","_bpx,%s",spname);
3645           emitcode ("mov","_bpx+1,esp");
3646           adjustEsp("_bpx+1");
3647       } else {
3648           if (options.useXstack)
3649           {
3650               emitcode ("mov", "r0,%s", spname);
3651               emitcode ("mov", "a,_bp");
3652               emitcode ("movx", "@r0,a");
3653               emitcode ("inc", "%s", spname);
3654           } else {
3655               /* set up the stack */
3656               emitcode ("push", "_bp"); /* save the callers stack  */
3657           }
3658           emitcode ("mov", "_bp,%s", spname);
3659       }
3660   }
3661
3662   /* adjust the stack for the function */
3663   if (sym->stack) {
3664       int i = sym->stack;
3665       if (options.stack10bit) {
3666           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3667           assert (sym->recvSize <= 4);
3668           if (sym->stack <= 8) {
3669               while (i--) emitcode ("push","acc");
3670           } else {
3671               PROTECT_SP;
3672               emitcode ("mov","a,sp");
3673               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3674               emitcode ("mov","sp,a");
3675               emitcode ("mov","a,esp");
3676               adjustEsp("a");
3677               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3678               emitcode ("mov","esp,a");
3679               UNPROTECT_SP;
3680           }
3681       } else {
3682           if (i > 256)
3683               werror (W_STACK_OVERFLOW, sym->name);
3684
3685           if (i > 3 && sym->recvSize < 4) {
3686
3687               emitcode ("mov", "a,sp");
3688               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3689               emitcode ("mov", "sp,a");
3690
3691           } else
3692               while (i--)
3693                   emitcode ("inc", "sp");
3694       }
3695   }
3696
3697   if (sym->xstack)
3698     {
3699
3700       emitcode ("mov", "a,_spx");
3701       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3702       emitcode ("mov", "_spx,a");
3703     }
3704
3705   /* if critical function then turn interrupts off */
3706   if (IFFUNC_ISCRITICAL (ftype))
3707     {
3708       symbol *tlbl = newiTempLabel (NULL);
3709       emitcode ("setb", "c");
3710       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3711       emitcode ("clr", "c");
3712       emitLabel (tlbl);
3713       emitcode ("push", "psw"); /* save old ea via c in psw */
3714     }
3715 }
3716
3717 /*-----------------------------------------------------------------*/
3718 /* genEndFunction - generates epilogue for functions               */
3719 /*-----------------------------------------------------------------*/
3720 static void
3721 genEndFunction (iCode * ic)
3722 {
3723   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3724   lineNode *lnp = lineCurr;
3725   bitVect *regsUsed;
3726   bitVect *regsUsedPrologue;
3727   bitVect *regsUnneeded;
3728   int idx;
3729
3730   D (emitcode (";", "genEndFunction"));
3731
3732   _G.currentFunc = NULL;
3733   if (IFFUNC_ISNAKED(sym->type))
3734   {
3735       emitcode(";", "naked function: no epilogue.");
3736       if (options.debug && currFunc)
3737         debugFile->writeEndFunction (currFunc, ic, 0);
3738       return;
3739   }
3740
3741   if (IFFUNC_ISCRITICAL (sym->type))
3742     {
3743       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3744         {
3745           emitcode ("rlc", "a");   /* save c in a */
3746           emitcode ("pop", "psw"); /* restore ea via c in psw */
3747           emitcode ("mov", "ea,c");
3748           emitcode ("rrc", "a");   /* restore c from a */
3749         }
3750       else
3751         {
3752           emitcode ("pop", "psw"); /* restore ea via c in psw */
3753           emitcode ("mov", "ea,c");
3754         }
3755     }
3756
3757   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3758        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3759
3760       if (options.stack10bit) {
3761           PROTECT_SP;
3762           emitcode ("mov", "sp,_bpx", spname);
3763           emitcode ("mov", "esp,_bpx+1", spname);
3764           UNPROTECT_SP;
3765       } else {
3766           emitcode ("mov", "%s,_bp", spname);
3767       }
3768   }
3769
3770   /* if use external stack but some variables were
3771      added to the local stack then decrement the
3772      local stack */
3773   if (options.useXstack && sym->stack) {
3774       emitcode ("mov", "a,sp");
3775       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3776       emitcode ("mov", "sp,a");
3777   }
3778
3779
3780   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3781        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3782
3783       if (options.useXstack) {
3784           emitcode ("mov", "r0,%s", spname);
3785           emitcode ("movx", "a,@r0");
3786           emitcode ("mov", "_bp,a");
3787           emitcode ("dec", "%s", spname);
3788       } else {
3789           if (options.stack10bit) {
3790               emitcode ("pop", "_bpx+1");
3791               emitcode ("pop", "_bpx");
3792           } else {
3793               emitcode ("pop", "_bp");
3794           }
3795       }
3796   }
3797
3798   /* restore the register bank  */
3799   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3800   {
3801     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3802      || !options.useXstack)
3803     {
3804         /* Special case of ISR using non-zero bank with useXstack
3805          * is handled below.
3806          */
3807         emitcode ("pop", "psw");
3808     }
3809   }
3810
3811   if (IFFUNC_ISISR (sym->type))
3812     { /* is ISR */
3813
3814       /* now we need to restore the registers */
3815       /* if this isr has no bank i.e. is going to
3816          run with bank 0 , then we need to save more
3817          registers :-) */
3818       if (!FUNC_REGBANK (sym->type))
3819         {
3820           int i;
3821           /* if this function does not call any other
3822              function then we can be economical and
3823              save only those registers that are used */
3824           if (!IFFUNC_HASFCALL(sym->type))
3825             {
3826               /* if any registers used */
3827               if (sym->regsUsed)
3828                 {
3829                   bool bits_popped = FALSE;
3830                   /* save the registers used */
3831                   for (i = sym->regsUsed->size; i >= 0; i--)
3832                     {
3833                       if (bitVectBitValue (sym->regsUsed, i))
3834                         bits_popped = popReg (i, bits_popped);
3835                     }
3836                 }
3837             }
3838           else
3839             {
3840               /* this function has a function call. We cannot
3841                  determine register usage so we will have to pop the
3842                  entire bank */
3843               if (options.parms_in_bank1) {
3844                   for (i = 7 ; i >= 0 ; i-- ) {
3845                       emitcode ("pop","%s",rb1regs[i]);
3846                   }
3847               }
3848               unsaveRBank (0, ic, FALSE);
3849             }
3850         }
3851       else
3852         {
3853             /* This ISR uses a non-zero bank.
3854              *
3855              * Restore any register banks saved by genFunction
3856              * in reverse order.
3857              */
3858             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3859             int ix;
3860
3861             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3862             {
3863                 if (savedBanks & (1 << ix))
3864                 {
3865                     unsaveRBank(ix, NULL, FALSE);
3866                 }
3867             }
3868
3869             if (options.useXstack)
3870             {
3871                 /* Restore bank AFTER calling unsaveRBank,
3872                  * since it can trash r0.
3873                  */
3874                 emitcode ("pop", "psw");
3875             }
3876         }
3877
3878       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3879         {
3880           if (options.stack10bit)
3881             {
3882               emitcode ("pop", DP2_RESULT_REG);
3883               emitcode ("pop", "dpx1");
3884               emitcode ("pop", "dph1");
3885               emitcode ("pop", "dpl1");
3886             }
3887           emitcode ("pop", "dps");
3888           emitcode ("pop", "dpx");
3889         }
3890       if (!inExcludeList ("dph"))
3891         emitcode ("pop", "dph");
3892       if (!inExcludeList ("dpl"))
3893         emitcode ("pop", "dpl");
3894       if (!inExcludeList ("b"))
3895         emitcode ("pop", "b");
3896       if (!inExcludeList ("acc"))
3897         emitcode ("pop", "acc");
3898
3899       /* if debug then send end of function */
3900       if (options.debug && currFunc)
3901         {
3902           debugFile->writeEndFunction (currFunc, ic, 1);
3903         }
3904
3905       emitcode ("reti", "");
3906     }
3907   else
3908     {
3909       if (IFFUNC_CALLEESAVES(sym->type))
3910         {
3911           int i;
3912
3913           /* if any registers used */
3914           if (sym->regsUsed)
3915             {
3916               /* save the registers used */
3917               for (i = sym->regsUsed->size; i >= 0; i--)
3918                 {
3919                   if (bitVectBitValue (sym->regsUsed, i))
3920                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3921                 }
3922             }
3923         }
3924
3925       /* if debug then send end of function */
3926       if (options.debug && currFunc)
3927         {
3928           debugFile->writeEndFunction (currFunc, ic, 1);
3929         }
3930
3931       emitcode ("ret", "");
3932     }
3933
3934   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3935     return;
3936
3937   /* If this was an interrupt handler using bank 0 that called another */
3938   /* function, then all registers must be saved; nothing to optimized. */
3939   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3940       && !FUNC_REGBANK(sym->type))
3941     return;
3942
3943   /* There are no push/pops to optimize if not callee-saves or ISR */
3944   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3945     return;
3946
3947   /* If there were stack parameters, we cannot optimize without also    */
3948   /* fixing all of the stack offsets; this is too dificult to consider. */
3949   if (FUNC_HASSTACKPARM(sym->type))
3950     return;
3951
3952   /* Compute the registers actually used */
3953   regsUsed = newBitVect (ds390_nRegs);
3954   regsUsedPrologue = newBitVect (ds390_nRegs);
3955   while (lnp)
3956     {
3957       if (lnp->ic && lnp->ic->op == FUNCTION)
3958         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3959       else
3960         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3961
3962       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3963           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3964         break;
3965       if (!lnp->prev)
3966         break;
3967       lnp = lnp->prev;
3968     }
3969
3970   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3971       && !bitVectBitValue (regsUsed, DPS_IDX))
3972     {
3973       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3974     }
3975
3976   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3977       && !bitVectBitValue (regsUsed, CND_IDX))
3978     {
3979       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3980       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3981           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3982         bitVectUnSetBit (regsUsed, CND_IDX);
3983     }
3984   else
3985     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3986
3987   /* If this was an interrupt handler that called another function */
3988   /* function, then assume working registers may be modified by it. */
3989   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3990     {
3991       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3992       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3993       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3994       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3995       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3996       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3997       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3998       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3999       regsUsed = bitVectSetBit (regsUsed, B_IDX);
4000       regsUsed = bitVectSetBit (regsUsed, A_IDX);
4001       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
4002     }
4003
4004   /* Remove the unneeded push/pops */
4005   regsUnneeded = newBitVect (ds390_nRegs);
4006   while (lnp)
4007     {
4008       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
4009         {
4010           if (!strncmp(lnp->line, "push", 4))
4011             {
4012               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
4013               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4014                 {
4015                   connectLine (lnp->prev, lnp->next);
4016                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4017                 }
4018             }
4019           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4020             {
4021               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4022               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4023                 {
4024                   connectLine (lnp->prev, lnp->next);
4025                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4026                 }
4027             }
4028         }
4029       lnp = lnp->next;
4030     }
4031
4032   for (idx = 0; idx < regsUnneeded->size; idx++)
4033     if (bitVectBitValue (regsUnneeded, idx))
4034       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4035
4036   freeBitVect (regsUnneeded);
4037   freeBitVect (regsUsed);
4038   freeBitVect (regsUsedPrologue);
4039 }
4040
4041 /*-----------------------------------------------------------------*/
4042 /* genJavaNativeRet - generate code for return JavaNative          */
4043 /*-----------------------------------------------------------------*/
4044 static void genJavaNativeRet(iCode *ic)
4045 {
4046     int i, size;
4047
4048     aopOp (IC_LEFT (ic), ic, FALSE,
4049            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4050     size = AOP_SIZE (IC_LEFT (ic));
4051
4052     assert (size <= 4);
4053
4054     /* it is assigned to GPR0-R3 then push them */
4055     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4056         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4057         for (i = 0 ; i < size ; i++ ) {
4058             emitcode ("push","%s",
4059                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4060         }
4061         for (i = (size-1) ; i >= 0 ; i--) {
4062             emitcode ("pop","a%s",javaRet[i]);
4063         }
4064     } else {
4065         for (i = 0 ; i < size ; i++)
4066             emitcode ("mov","%s,%s",javaRet[i],
4067                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4068     }
4069     for (i = size ; i < 4 ; i++ )
4070             emitcode ("mov","%s,#0",javaRet[i]);
4071     return;
4072 }
4073
4074 /*-----------------------------------------------------------------*/
4075 /* genRet - generate code for return statement                     */
4076 /*-----------------------------------------------------------------*/
4077 static void
4078 genRet (iCode * ic)
4079 {
4080   int size, offset = 0, pushed = 0;
4081
4082   D (emitcode (";", "genRet"));
4083
4084   /* if we have no return value then
4085      just generate the "ret" */
4086   if (!IC_LEFT (ic))
4087     goto jumpret;
4088
4089   /* if this is a JavaNative function then return
4090      value in different register */
4091   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4092       genJavaNativeRet(ic);
4093       goto jumpret;
4094   }
4095   /* we have something to return then
4096      move the return value into place */
4097   aopOp (IC_LEFT (ic), ic, FALSE,
4098          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4099   size = AOP_SIZE (IC_LEFT (ic));
4100
4101   _startLazyDPSEvaluation ();
4102
4103   if (IS_BIT(_G.currentFunc->etype))
4104     {
4105       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4106       size = 0;
4107     }
4108
4109   while (size--)
4110     {
4111       char *l;
4112       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4113         {
4114           l = aopGet (IC_LEFT (ic), offset++,
4115                       FALSE, TRUE, NULL);
4116           emitcode ("push", "%s", l);
4117           pushed++;
4118         }
4119       else
4120         {
4121           /* Since A is the last element of fReturn,
4122            * it is OK to clobber it in the aopGet.
4123            */
4124           l = aopGet (IC_LEFT (ic), offset,
4125                       FALSE, FALSE, NULL);
4126           if (strcmp (fReturn[offset], l))
4127             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4128         }
4129     }
4130   _endLazyDPSEvaluation ();
4131
4132   while (pushed)
4133     {
4134       pushed--;
4135       if (strcmp (fReturn[pushed], "a"))
4136         emitcode ("pop", fReturn[pushed]);
4137       else
4138         emitcode ("pop", "acc");
4139     }
4140   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4141
4142 jumpret:
4143   /* generate a jump to the return label
4144      if the next is not the return statement */
4145   if (!(ic->next && ic->next->op == LABEL &&
4146         IC_LABEL (ic->next) == returnLabel))
4147
4148     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4149
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genLabel - generates a label                                    */
4154 /*-----------------------------------------------------------------*/
4155 static void
4156 genLabel (iCode * ic)
4157 {
4158   /* special case never generate */
4159   if (IC_LABEL (ic) == entryLabel)
4160     return;
4161
4162   D (emitcode (";", "genLabel"));
4163
4164   emitLabel (IC_LABEL (ic));
4165 }
4166
4167 /*-----------------------------------------------------------------*/
4168 /* genGoto - generates a ljmp                                      */
4169 /*-----------------------------------------------------------------*/
4170 static void
4171 genGoto (iCode * ic)
4172 {
4173   D (emitcode (";", "genGoto"));
4174
4175   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4176 }
4177
4178 /*-----------------------------------------------------------------*/
4179 /* findLabelBackwards: walks back through the iCode chain looking  */
4180 /* for the given label. Returns number of iCode instructions     */
4181 /* between that label and given ic.          */
4182 /* Returns zero if label not found.          */
4183 /*-----------------------------------------------------------------*/
4184 static int
4185 findLabelBackwards (iCode * ic, int key)
4186 {
4187   int count = 0;
4188
4189   while (ic->prev)
4190     {
4191       ic = ic->prev;
4192       count++;
4193
4194       /* If we have any pushes or pops, we cannot predict the distance.
4195          I don't like this at all, this should be dealt with in the
4196          back-end */
4197       if (ic->op == IPUSH || ic->op == IPOP) {
4198         return 0;
4199       }
4200
4201       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4202         {
4203           /* printf("findLabelBackwards = %d\n", count); */
4204           return count;
4205         }
4206     }
4207
4208   return 0;
4209 }
4210
4211 /*-----------------------------------------------------------------*/
4212 /* genPlusIncr :- does addition with increment if possible         */
4213 /*-----------------------------------------------------------------*/
4214 static bool
4215 genPlusIncr (iCode * ic)
4216 {
4217   unsigned int icount;
4218   unsigned int size = getDataSize (IC_RESULT (ic));
4219
4220   /* will try to generate an increment */
4221   /* if the right side is not a literal
4222      we cannot */
4223   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4224     return FALSE;
4225
4226   /* if the literal value of the right hand side
4227      is greater than 4 then it is not worth it */
4228   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4229     return FALSE;
4230
4231   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4232       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4233       while (icount--) {
4234           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4235       }
4236       return TRUE;
4237   }
4238   /* if increment 16 bits in register */
4239   if (
4240        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4241        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4242        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4243        (size > 1) &&
4244        (icount == 1))
4245     {
4246       symbol  *tlbl;
4247       int     emitTlbl;
4248       int     labelRange;
4249       char    *l;
4250
4251       /* If the next instruction is a goto and the goto target
4252        * is <= 5 instructions previous to this, we can generate
4253        * jumps straight to that target.
4254        */
4255       if (ic->next && ic->next->op == GOTO
4256           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4257           && labelRange <= 5)
4258         {
4259           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4260           tlbl = IC_LABEL (ic->next);
4261           emitTlbl = 0;
4262         }
4263       else
4264         {
4265           tlbl = newiTempLabel (NULL);
4266           emitTlbl = 1;
4267         }
4268       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4269       emitcode ("inc", "%s", l);
4270
4271       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4272           IS_AOP_PREG (IC_RESULT (ic)))
4273         {
4274           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4275         }
4276       else
4277         {
4278           emitcode ("clr", "a");
4279           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4280         }
4281
4282       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4283       emitcode ("inc", "%s", l);
4284       if (size > 2)
4285         {
4286           if (!strcmp(l, "acc"))
4287             {
4288                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4289             }
4290           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4291                    IS_AOP_PREG (IC_RESULT (ic)))
4292             {
4293                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4294             }
4295           else
4296             {
4297                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4298             }
4299
4300           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4301           emitcode ("inc", "%s", l);
4302         }
4303       if (size > 3)
4304         {
4305           if (!strcmp(l, "acc"))
4306             {
4307                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4308             }
4309           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4310                    IS_AOP_PREG (IC_RESULT (ic)))
4311             {
4312                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4313             }
4314           else
4315             {
4316                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4317             }
4318
4319           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4320           emitcode ("inc", "%s", l);
4321         }
4322
4323       if (emitTlbl)
4324         {
4325           emitLabel (tlbl);
4326         }
4327       return TRUE;
4328     }
4329
4330   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4331       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4332       options.model == MODEL_FLAT24 )
4333     {
4334       if (IC_RESULT(ic)->isGptr)
4335         {
4336           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4337         }
4338       switch (size) {
4339       case 3:
4340           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4341       case 2:
4342           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4343       case 1:
4344           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4345           break;
4346       }
4347       while (icount--)
4348         emitcode ("inc", "dptr");
4349       return TRUE;
4350   }
4351
4352   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4353       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4354       icount <= 5 ) {
4355       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4356       while (icount--)
4357         emitcode ("inc", "dptr");
4358       emitcode ("mov", "dps,#0");
4359       return TRUE;
4360   }
4361
4362   /* if the sizes are greater than 1 then we cannot */
4363   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4364       AOP_SIZE (IC_LEFT (ic)) > 1)
4365     return FALSE;
4366
4367   /* we can if the aops of the left & result match or
4368      if they are in registers and the registers are the
4369      same */
4370   if (
4371        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4372        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4373        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4374     {
4375       if (icount > 3)
4376         {
4377           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4378           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4379           aopPut (IC_RESULT (ic), "a", 0);
4380         }
4381       else
4382         {
4383           _startLazyDPSEvaluation ();
4384           while (icount--)
4385             {
4386               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4387             }
4388           _endLazyDPSEvaluation ();
4389         }
4390
4391       return TRUE;
4392     }
4393
4394   return FALSE;
4395 }
4396
4397 /*-----------------------------------------------------------------*/
4398 /* outBitAcc - output a bit in acc                                 */
4399 /*-----------------------------------------------------------------*/
4400 static void
4401 outBitAcc (operand * result)
4402 {
4403   symbol *tlbl = newiTempLabel (NULL);
4404   /* if the result is a bit */
4405   if (AOP_TYPE (result) == AOP_CRY)
4406     {
4407       aopPut (result, "a", 0);
4408     }
4409   else
4410     {
4411       emitcode ("jz", "!tlabel", tlbl->key + 100);
4412       emitcode ("mov", "a,%s", one);
4413       emitLabel (tlbl);
4414       outAcc (result);
4415     }
4416 }
4417
4418 /*-----------------------------------------------------------------*/
4419 /* genPlusBits - generates code for addition of two bits           */
4420 /*-----------------------------------------------------------------*/
4421 static void
4422 genPlusBits (iCode * ic)
4423 {
4424   D (emitcode (";", "genPlusBits"));
4425
4426   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4427     {
4428       symbol *lbl = newiTempLabel (NULL);
4429       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4430       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4431       emitcode ("cpl", "c");
4432       emitLabel (lbl);
4433       outBitC (IC_RESULT (ic));
4434     }
4435   else
4436     {
4437       emitcode ("clr", "a");
4438       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4439       emitcode ("rlc", "a");
4440       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4441       emitcode ("addc", "a,%s", zero);
4442       outAcc (IC_RESULT (ic));
4443     }
4444 }
4445
4446 static void
4447 adjustArithmeticResult (iCode * ic)
4448 {
4449   if (opIsGptr (IC_RESULT (ic)) &&
4450       opIsGptr (IC_LEFT (ic)) &&
4451       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4452     {
4453       aopPut (IC_RESULT (ic),
4454               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4455               GPTRSIZE - 1);
4456     }
4457
4458   if (opIsGptr (IC_RESULT (ic)) &&
4459       opIsGptr (IC_RIGHT (ic)) &&
4460       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4461     {
4462       aopPut (IC_RESULT (ic),
4463               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4464               GPTRSIZE - 1);
4465     }
4466
4467   if (opIsGptr (IC_RESULT (ic)) &&
4468       IC_LEFT (ic) && AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4469       IC_RIGHT (ic) && AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4470       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4471       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4472     {
4473       char buffer[5];
4474       SNPRINTF (buffer, sizeof(buffer),
4475                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4476       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4477     }
4478 }
4479
4480 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4481 // generates the result if possible. If result is generated, returns TRUE; otherwise
4482 // returns false and caller must deal with fact that result isn't aopOp'd.
4483 bool aopOp3(iCode * ic)
4484 {
4485     bool dp1InUse, dp2InUse;
4486     bool useDp2;
4487
4488     // First, generate the right opcode. DPTR may be used if neither left nor result are
4489     // of type AOP_STR.
4490
4491 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4492 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4493 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4494 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4495 //      );
4496 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4497 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4498 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4499 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4500 //      );
4501
4502     // Right uses DPTR unless left or result is an AOP_STR; however,
4503     // if right is an AOP_STR, it must use DPTR regardless.
4504     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4505      && !AOP_IS_STR (IC_RIGHT (ic)))
4506     {
4507         useDp2 = TRUE;
4508     }
4509     else
4510     {
4511         useDp2 = FALSE;
4512     }
4513
4514     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4515
4516     // if the right used DPTR, left MUST use DPTR2.
4517     // if the right used DPTR2, left MUST use DPTR.
4518     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4519     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4520     // enabling us to assign DPTR to result.
4521
4522     if (AOP_USESDPTR (IC_RIGHT (ic)))
4523     {
4524         useDp2 = TRUE;
4525     }
4526     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4527     {
4528         useDp2 = FALSE;
4529     }
4530     else
4531     {
4532         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4533         {
4534             useDp2 = TRUE;
4535         }
4536         else
4537         {
4538             useDp2 = FALSE;
4539         }
4540     }
4541
4542     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4543
4544
4545     // We've op'd the left & right. So, if left or right are the same operand as result,
4546     // we know aopOp will succeed, and we can just do it & bail.
4547     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4548       {
4549         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4550         return TRUE;
4551       }
4552     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4553       {
4554 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4555         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4556         return TRUE;
4557       }
4558
4559     // Operands may be equivalent (but not equal) if they share a spill location. If
4560     // so, use the same DPTR or DPTR2.
4561     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4562       {
4563         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4564         return TRUE;
4565       }
4566     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4567       {
4568         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4569         return TRUE;
4570       }
4571
4572     // Note which dptrs are currently in use.
4573     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4574     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4575
4576     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4577     // generate it.
4578     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4579     {
4580         return FALSE;
4581     }
4582
4583     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4584     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4585     {
4586         return FALSE;
4587     }
4588
4589     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4590     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4591     {
4592         return FALSE;
4593     }
4594
4595     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4596
4597     // Some sanity checking...
4598     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4599     {
4600         fprintf(stderr,
4601                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4602                 __FILE__, __LINE__, ic->filename, ic->lineno);
4603         emitcode(";", ">>> unexpected DPTR here.");
4604     }
4605
4606     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4607     {
4608         fprintf(stderr,
4609                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4610                 __FILE__, __LINE__, ic->filename, ic->lineno);
4611         emitcode(";", ">>> unexpected DPTR2 here.");
4612     }
4613
4614     return TRUE;
4615 }
4616
4617 // Macro to aopOp all three operands of an ic. If this cannot be done,
4618 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4619 // will be set TRUE. The caller must then handle the case specially, noting
4620 // that the IC_RESULT operand is not aopOp'd.
4621 //
4622 #define AOP_OP_3_NOFATAL(ic, rc) \
4623             do { rc = !aopOp3(ic); } while (0)
4624
4625 // aopOp the left & right operands of an ic.
4626 #define AOP_OP_2(ic) \
4627     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4628     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4629
4630 // convienience macro.
4631 #define AOP_SET_LOCALS(ic) \
4632     left = IC_LEFT(ic); \
4633     right = IC_RIGHT(ic); \
4634     result = IC_RESULT(ic);
4635
4636
4637 // Given an integer value of pushedSize bytes on the stack,
4638 // adjust it to be resultSize bytes, either by discarding
4639 // the most significant bytes or by zero-padding.
4640 //
4641 // On exit from this macro, pushedSize will have been adjusted to
4642 // equal resultSize, and ACC may be trashed.
4643 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4644       /* If the pushed data is bigger than the result,          \
4645        * simply discard unused bytes. Icky, but works.          \
4646        */                                                       \
4647       while (pushedSize > resultSize)                           \
4648       {                                                         \
4649           D (emitcode (";", "discarding unused result byte.")); \
4650           emitcode ("pop", "acc");                              \
4651           pushedSize--;                                         \
4652       }                                                         \
4653       if (pushedSize < resultSize)                              \
4654       {                                                         \
4655           emitcode ("clr", "a");                                \
4656           /* Conversly, we haven't pushed enough here.          \
4657            * just zero-pad, and all is well.                    \
4658            */                                                   \
4659           while (pushedSize < resultSize)                       \
4660           {                                                     \
4661               emitcode("push", "acc");                          \
4662               pushedSize++;                                     \
4663           }                                                     \
4664       }                                                         \
4665       assert(pushedSize == resultSize);
4666
4667 /*-----------------------------------------------------------------*/
4668 /* genPlus - generates code for addition                           */
4669 /*-----------------------------------------------------------------*/
4670 static void
4671 genPlus (iCode * ic)
4672 {
4673   int size, offset = 0;
4674   bool pushResult;
4675   int rSize;
4676   bool swappedLR = FALSE;
4677
4678   D (emitcode (";", "genPlus"));
4679
4680   /* special cases :- */
4681   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4682       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4683       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4684       size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4685       if (size <= 9) {
4686           while (size--) emitcode ("inc","dptr");
4687       } else {
4688           emitcode ("mov", "a,dpl");
4689           emitcode ("add", "a,#!constbyte", size & 0xff);
4690           emitcode ("mov", "dpl,a");
4691           emitcode ("mov", "a,dph");
4692           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4693           emitcode ("mov", "dph,a");
4694           emitcode ("mov", "a,dpx");
4695           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4696           emitcode ("mov", "dpx,a");
4697       }
4698       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4699       return ;
4700   }
4701   if ( IS_SYMOP (IC_LEFT (ic)) &&
4702        OP_SYMBOL (IC_LEFT (ic))->remat &&
4703        isOperandInFarSpace (IC_RIGHT (ic))) {
4704       operand *op = IC_RIGHT(ic);
4705       IC_RIGHT(ic) = IC_LEFT(ic);
4706       IC_LEFT(ic) = op;
4707   }
4708
4709   AOP_OP_3_NOFATAL (ic, pushResult);
4710
4711   if (pushResult)
4712     {
4713       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4714     }
4715
4716   if (!pushResult)
4717     {
4718       /* if literal, literal on the right or
4719          if left requires ACC or right is already
4720          in ACC */
4721       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4722           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4723           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4724         {
4725           operand *t = IC_RIGHT (ic);
4726           IC_RIGHT (ic) = IC_LEFT (ic);
4727           IC_LEFT (ic) = t;
4728           swappedLR = TRUE;
4729           D (emitcode (";", "Swapped plus args."));
4730         }
4731
4732       /* if both left & right are in bit
4733          space */
4734       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4735           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4736         {
4737           genPlusBits (ic);
4738           goto release;
4739         }
4740
4741       /* if left in bit space & right literal */
4742       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4743           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4744         {
4745           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4746           /* if result in bit space */
4747           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4748             {
4749               if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4750                 emitcode ("cpl", "c");
4751               outBitC (IC_RESULT (ic));
4752             }
4753           else
4754             {
4755               size = getDataSize (IC_RESULT (ic));
4756               _startLazyDPSEvaluation ();
4757               while (size--)
4758                 {
4759                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4760                   emitcode ("addc", "a,%s", zero);
4761                   aopPut (IC_RESULT (ic), "a", offset++);
4762                 }
4763               _endLazyDPSEvaluation ();
4764             }
4765           goto release;
4766         }
4767
4768       /* if I can do an increment instead
4769          of add then GOOD for ME */
4770       if (genPlusIncr (ic) == TRUE)
4771         {
4772           D (emitcode (";", "did genPlusIncr"));
4773           goto release;
4774         }
4775
4776     }
4777   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4778
4779   _startLazyDPSEvaluation ();
4780   while (size--)
4781     {
4782       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4783         {
4784           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4785           if (offset == 0)
4786             emitcode ("add", "a,%s",
4787                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4788           else
4789             emitcode ("addc", "a,%s",
4790                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4791         }
4792       else
4793         {
4794           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4795           {
4796               /* right is going to use ACC or we would have taken the
4797                * above branch.
4798                */
4799               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4800               TR_AP("#3");
4801               D(emitcode(";", "+ AOP_ACC special case."););
4802               emitcode("xch", "a, %s", DP2_RESULT_REG);
4803           }
4804           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4805           if (offset == 0)
4806           {
4807             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4808             {
4809                 TR_AP("#4");
4810                 emitcode("add", "a, %s", DP2_RESULT_REG);
4811             }
4812             else
4813             {
4814                 emitcode ("add", "a,%s",
4815                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4816                                   DP2_RESULT_REG));
4817             }
4818           }
4819           else
4820           {
4821             emitcode ("addc", "a,%s",
4822                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4823                           DP2_RESULT_REG));
4824           }
4825         }
4826       if (!pushResult)
4827         {
4828           aopPut (IC_RESULT (ic), "a", offset);
4829         }
4830       else
4831         {
4832           emitcode ("push", "acc");
4833         }
4834       offset++;
4835     }
4836   _endLazyDPSEvaluation ();
4837
4838   if (pushResult)
4839     {
4840       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4841
4842       size = getDataSize (IC_LEFT (ic));
4843       rSize = getDataSize (IC_RESULT (ic));
4844
4845       ADJUST_PUSHED_RESULT(size, rSize);
4846
4847       _startLazyDPSEvaluation ();
4848       while (size--)
4849         {
4850           emitcode ("pop", "acc");
4851           aopPut (IC_RESULT (ic), "a", size);
4852         }
4853       _endLazyDPSEvaluation ();
4854     }
4855
4856   adjustArithmeticResult (ic);
4857
4858 release:
4859   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4860   if (!swappedLR)
4861     {
4862       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4863       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4864     }
4865   else
4866     {
4867       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4868       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4869     }
4870 }
4871
4872 /*-----------------------------------------------------------------*/
4873 /* genMinusDec :- does subtraction with decrement if possible      */
4874 /*-----------------------------------------------------------------*/
4875 static bool
4876 genMinusDec (iCode * ic)
4877 {
4878   unsigned int icount;
4879   unsigned int size = getDataSize (IC_RESULT (ic));
4880
4881   /* will try to generate an increment */
4882   /* if the right side is not a literal
4883      we cannot */
4884   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4885     return FALSE;
4886
4887   /* if the literal value of the right hand side
4888      is greater than 4 then it is not worth it */
4889   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4890     return FALSE;
4891
4892   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4893       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4894       while (icount--) {
4895           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4896       }
4897       return TRUE;
4898   }
4899   /* if decrement 16 bits in register */
4900   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4901       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4902       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4903       (size > 1) &&
4904       (icount == 1))
4905     {
4906       symbol *tlbl;
4907       int    emitTlbl;
4908       int    labelRange;
4909       char   *l;
4910
4911       /* If the next instruction is a goto and the goto target
4912          * is <= 5 instructions previous to this, we can generate
4913          * jumps straight to that target.
4914        */
4915       if (ic->next && ic->next->op == GOTO
4916           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4917           && labelRange <= 5)
4918         {
4919           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4920           tlbl = IC_LABEL (ic->next);
4921           emitTlbl = 0;
4922         }
4923       else
4924         {
4925           tlbl = newiTempLabel (NULL);
4926           emitTlbl = 1;
4927         }
4928
4929       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4930       emitcode ("dec", "%s", l);
4931
4932       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4933           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4934           IS_AOP_PREG (IC_RESULT (ic)))
4935       {
4936           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4937       }
4938       else
4939       {
4940           emitcode ("mov", "a,#!constbyte",0xff);
4941           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4942       }
4943       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4944       emitcode ("dec", "%s", l);
4945       if (size > 2)
4946         {
4947             if (!strcmp(l, "acc"))
4948             {
4949                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4950             }
4951             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4952                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4953                      IS_AOP_PREG (IC_RESULT (ic)))
4954             {
4955                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4956             }
4957             else
4958             {
4959                 emitcode ("mov", "a,#!constbyte",0xff);
4960                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4961             }
4962             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4963             emitcode ("dec", "%s", l);
4964         }
4965       if (size > 3)
4966         {
4967             if (!strcmp(l, "acc"))
4968             {
4969                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4970             }
4971             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4972                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4973                      IS_AOP_PREG (IC_RESULT (ic)))
4974             {
4975                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4976             }
4977             else
4978             {
4979                 emitcode ("mov", "a,#!constbyte",0xff);
4980                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4981             }
4982             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4983             emitcode ("dec", "%s", l);
4984         }
4985       if (emitTlbl)
4986         {
4987           emitLabel (tlbl);
4988         }
4989       return TRUE;
4990     }
4991
4992   /* if the sizes are greater than 1 then we cannot */
4993   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4994       AOP_SIZE (IC_LEFT (ic)) > 1)
4995     return FALSE;
4996
4997   /* we can if the aops of the left & result match or
4998      if they are in registers and the registers are the
4999      same */
5000   if (
5001        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
5002        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
5003        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5004     {
5005       char *l;
5006
5007       if (aopGetUsesAcc (IC_LEFT (ic), 0))
5008         {
5009           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
5010           l = "a";
5011         }
5012       else
5013         {
5014           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5015         }
5016
5017       _startLazyDPSEvaluation ();
5018       while (icount--)
5019         {
5020           emitcode ("dec", "%s", l);
5021         }
5022       _endLazyDPSEvaluation ();
5023
5024       if (AOP_NEEDSACC (IC_RESULT (ic)))
5025         aopPut (IC_RESULT (ic), "a", 0);
5026
5027       return TRUE;
5028     }
5029
5030   return FALSE;
5031 }
5032
5033 /*-----------------------------------------------------------------*/
5034 /* addSign - complete with sign                                    */
5035 /*-----------------------------------------------------------------*/
5036 static void
5037 addSign (operand * result, int offset, int sign)
5038 {
5039   int size = (getDataSize (result) - offset);
5040   if (size > 0)
5041     {
5042       _startLazyDPSEvaluation();
5043       if (sign)
5044         {
5045           emitcode ("rlc", "a");
5046           emitcode ("subb", "a,acc");
5047           while (size--)
5048             {
5049               aopPut (result, "a", offset++);
5050             }
5051         }
5052       else
5053       {
5054         while (size--)
5055         {
5056           aopPut (result, zero, offset++);
5057         }
5058       }
5059       _endLazyDPSEvaluation();
5060     }
5061 }
5062
5063 /*-----------------------------------------------------------------*/
5064 /* genMinusBits - generates code for subtraction  of two bits      */
5065 /*-----------------------------------------------------------------*/
5066 static void
5067 genMinusBits (iCode * ic)
5068 {
5069   symbol *lbl = newiTempLabel (NULL);
5070
5071   D (emitcode (";", "genMinusBits"));
5072
5073   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5074     {
5075       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5076       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5077       emitcode ("cpl", "c");
5078       emitLabel (lbl);
5079       outBitC (IC_RESULT (ic));
5080     }
5081   else
5082     {
5083       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5084       emitcode ("subb", "a,acc");
5085       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5086       emitcode ("inc", "a");
5087       emitLabel (lbl);
5088       aopPut (IC_RESULT (ic), "a", 0);
5089       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5090     }
5091 }
5092
5093 /*-----------------------------------------------------------------*/
5094 /* genMinus - generates code for subtraction                       */
5095 /*-----------------------------------------------------------------*/
5096 static void
5097 genMinus (iCode * ic)
5098 {
5099     int size, offset = 0;
5100     int rSize;
5101     long lit = 0L;
5102     bool pushResult;
5103
5104     D (emitcode (";", "genMinus"));
5105
5106     AOP_OP_3_NOFATAL(ic, pushResult);
5107
5108     if (!pushResult)
5109     {
5110       /* special cases :- */
5111       /* if both left & right are in bit space */
5112       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5113           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5114         {
5115           genMinusBits (ic);
5116           goto release;
5117         }
5118
5119       /* if I can do an decrement instead
5120          of subtract then GOOD for ME */
5121       if (genMinusDec (ic) == TRUE)
5122         goto release;
5123
5124     }
5125
5126   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5127
5128   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5129     {
5130       CLRC;
5131     }
5132   else
5133     {
5134       lit = (long) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5135       lit = -lit;
5136     }
5137
5138
5139   /* if literal, add a,#-lit, else normal subb */
5140   _startLazyDPSEvaluation ();
5141   while (size--) {
5142       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5143           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5144               emitcode ("mov","b,%s",
5145                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5146               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5147               emitcode ("subb","a,b");
5148           } else {
5149               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5150               emitcode ("subb", "a,%s",
5151                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5152                                 DP2_RESULT_REG));
5153           }
5154       } else {
5155           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5156           /* first add without previous c */
5157           if (!offset) {
5158               if (!size && lit==-1) {
5159                   emitcode ("dec", "a");
5160               } else {
5161                   emitcode ("add", "a,#!constbyte",
5162                             (unsigned int) (lit & 0x0FFL));
5163               }
5164           } else {
5165               emitcode ("addc", "a,#!constbyte",
5166                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5167           }
5168       }
5169
5170       if (pushResult) {
5171           emitcode ("push", "acc");
5172       } else {
5173           aopPut (IC_RESULT (ic), "a", offset);
5174       }
5175       offset++;
5176   }
5177   _endLazyDPSEvaluation ();
5178
5179   if (pushResult)
5180     {
5181       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5182
5183       size = getDataSize (IC_LEFT (ic));
5184       rSize = getDataSize (IC_RESULT (ic));
5185
5186       ADJUST_PUSHED_RESULT(size, rSize);
5187
5188       _startLazyDPSEvaluation ();
5189       while (size--)
5190         {
5191           emitcode ("pop", "acc");
5192           aopPut (IC_RESULT (ic), "a", size);
5193         }
5194       _endLazyDPSEvaluation ();
5195     }
5196
5197   adjustArithmeticResult (ic);
5198
5199 release:
5200   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5201   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5202   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5203 }
5204
5205
5206 /*-----------------------------------------------------------------*/
5207 /* genMultbits :- multiplication of bits                           */
5208 /*-----------------------------------------------------------------*/
5209 static void
5210 genMultbits (operand * left,
5211              operand * right,
5212              operand * result,
5213              iCode   * ic)
5214 {
5215   D (emitcode (";", "genMultbits"));
5216
5217   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5218   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5219   aopOp(result, ic, TRUE, FALSE);
5220   outBitC (result);
5221 }
5222
5223 /*-----------------------------------------------------------------*/
5224 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5225 /*-----------------------------------------------------------------*/
5226 static void
5227 genMultOneByte (operand * left,
5228                 operand * right,
5229                 operand * result,
5230                 iCode   * ic)
5231 {
5232   symbol *lbl;
5233   int size;
5234   bool runtimeSign, compiletimeSign;
5235   bool lUnsigned, rUnsigned, pushedB;
5236
5237   /* (if two literals: the value is computed before) */
5238   /* if one literal, literal on the right */
5239   if (AOP_TYPE (left) == AOP_LIT)
5240     {
5241       operand *t = right;
5242       right = left;
5243       left = t;
5244       /* emitcode (";", "swapped left and right"); */
5245     }
5246   /* if no literal, unsigned on the right: shorter code */
5247   if (   AOP_TYPE (right) != AOP_LIT
5248       && SPEC_USIGN (getSpec (operandType (left))))
5249     {
5250       operand *t = right;
5251       right = left;
5252       left = t;
5253     }
5254
5255   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5256   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5257
5258   pushedB = pushB ();
5259
5260   if ((lUnsigned && rUnsigned)
5261 /* sorry, I don't know how to get size
5262    without calling aopOp (result,...);
5263    see Feature Request  */
5264       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5265                    no need to take care about the signedness! */
5266     {
5267       /* just an unsigned 8 * 8 = 8 multiply
5268          or 8u * 8u = 16u */
5269       /* emitcode (";","unsigned"); */
5270       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5271       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5272       emitcode ("mul", "ab");
5273
5274       _G.accInUse++;
5275       aopOp (result, ic, TRUE, FALSE);
5276       size = AOP_SIZE (result);
5277
5278       if (size < 1 || size > 2)
5279         {
5280           /* this should never happen */
5281           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5282                    size, __FILE__, lineno);
5283           exit (1);
5284         }
5285
5286       aopPut (result, "a", 0);
5287       _G.accInUse--;
5288       if (size == 2)
5289         aopPut (result, "b", 1);
5290
5291       popB (pushedB);
5292       return;
5293     }
5294
5295   /* we have to do a signed multiply */
5296   /* emitcode (";", "signed"); */
5297
5298   /* now sign adjust for both left & right */
5299
5300   /* let's see what's needed: */
5301   /* apply negative sign during runtime */
5302   runtimeSign = FALSE;
5303   /* negative sign from literals */
5304   compiletimeSign = FALSE;
5305
5306   if (!lUnsigned)
5307     {
5308       if (AOP_TYPE(left) == AOP_LIT)
5309         {
5310           /* signed literal */
5311           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5312           if (val < 0)
5313             compiletimeSign = TRUE;
5314         }
5315       else
5316         /* signed but not literal */
5317         runtimeSign = TRUE;
5318     }
5319
5320   if (!rUnsigned)
5321     {
5322       if (AOP_TYPE(right) == AOP_LIT)
5323         {
5324           /* signed literal */
5325           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5326           if (val < 0)
5327             compiletimeSign ^= TRUE;
5328         }
5329       else
5330         /* signed but not literal */
5331         runtimeSign = TRUE;
5332     }
5333
5334   /* initialize F0, which stores the runtime sign */
5335   if (runtimeSign)
5336     {
5337       if (compiletimeSign)
5338         emitcode ("setb", "F0"); /* set sign flag */
5339       else
5340         emitcode ("clr", "F0"); /* reset sign flag */
5341     }
5342
5343   /* save the signs of the operands */
5344   if (AOP_TYPE(right) == AOP_LIT)
5345     {
5346       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5347
5348       if (!rUnsigned && val < 0)
5349         emitcode ("mov", "b,#!constbyte", -val);
5350       else
5351         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5352     }
5353   else /* ! literal */
5354     {
5355       if (rUnsigned)  /* emitcode (";", "signed"); */
5356         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5357       else
5358         {
5359           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5360           lbl = newiTempLabel (NULL);
5361           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5362           emitcode ("cpl", "F0"); /* complement sign flag */
5363           emitcode ("cpl", "a");  /* 2's complement */
5364           emitcode ("inc", "a");
5365           emitLabel (lbl);
5366           emitcode ("mov", "b,a");
5367         }
5368     }
5369
5370   if (AOP_TYPE(left) == AOP_LIT)
5371     {
5372       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5373
5374       if (!lUnsigned && val < 0)
5375         emitcode ("mov", "a,#!constbyte", -val);
5376       else
5377         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5378     }
5379   else /* ! literal */
5380     {
5381       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5382
5383       if (!lUnsigned)  /* emitcode (";", "signed"); */
5384         {
5385           lbl = newiTempLabel (NULL);
5386           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5387           emitcode ("cpl", "F0"); /* complement sign flag */
5388           emitcode ("cpl", "a");  /* 2's complement */
5389           emitcode ("inc", "a");
5390           emitLabel (lbl);
5391         }
5392     }
5393
5394   /* now the multiplication */
5395   emitcode ("mul", "ab");
5396   _G.accInUse++;
5397   aopOp(result, ic, TRUE, FALSE);
5398   size = AOP_SIZE (result);
5399
5400   if (size < 1 || size > 2)
5401     {
5402       /* this should never happen */
5403       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5404                size, __FILE__, lineno);
5405       exit (1);
5406     }
5407
5408   if (runtimeSign || compiletimeSign)
5409     {
5410       lbl = newiTempLabel (NULL);
5411       if (runtimeSign)
5412         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5413       emitcode ("cpl", "a"); /* lsb 2's complement */
5414       if (size != 2)
5415         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5416       else
5417         {
5418           emitcode ("add", "a,#1"); /* this sets carry flag */
5419           emitcode ("xch", "a,b");
5420           emitcode ("cpl", "a"); /* msb 2's complement */
5421           emitcode ("addc", "a,#0");
5422           emitcode ("xch", "a,b");
5423         }
5424       emitLabel (lbl);
5425     }
5426   aopPut (result, "a", 0);
5427   _G.accInUse--;
5428   if (size == 2)
5429     aopPut (result, "b", 1);
5430
5431   popB (pushedB);
5432 }
5433
5434 /*-----------------------------------------------------------------*/
5435 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5436 /*-----------------------------------------------------------------*/
5437 static void genMultTwoByte (operand *left, operand *right,
5438                             operand *result, iCode *ic)
5439 {
5440         sym_link *retype = getSpec(operandType(right));
5441         sym_link *letype = getSpec(operandType(left));
5442         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5443         symbol *lbl;
5444
5445         if (AOP_TYPE (left) == AOP_LIT) {
5446                 operand *t = right;
5447                 right = left;
5448                 left = t;
5449         }
5450         /* save EA bit in F1 */
5451         lbl = newiTempLabel(NULL);
5452         emitcode ("setb","F1");
5453         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5454         emitcode ("clr","F1");
5455         emitLabel (lbl);
5456
5457         /* load up MB with right */
5458         if (!umult) {
5459                 emitcode("clr","F0");
5460                 if (AOP_TYPE(right) == AOP_LIT) {
5461                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5462                         if (val < 0) {
5463                                 emitcode("setb","F0");
5464                                 val = -val;
5465                         }
5466                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5467                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5468                 } else {
5469                         lbl = newiTempLabel(NULL);
5470                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5471                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5472                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5473                         emitcode ("xch", "a,b");
5474                         emitcode ("cpl","a");
5475                         emitcode ("add", "a,#1");
5476                         emitcode ("xch", "a,b");
5477                         emitcode ("cpl", "a"); // msb
5478                         emitcode ("addc", "a,#0");
5479                         emitcode ("setb","F0");
5480                         emitLabel (lbl);
5481                         emitcode ("mov","mb,b");
5482                         emitcode ("mov","mb,a");
5483                 }
5484         } else {
5485                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5486                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5487         }
5488         /* load up MA with left */
5489         if (!umult) {
5490                 lbl = newiTempLabel(NULL);
5491                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5492                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5493                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5494                 emitcode ("xch", "a,b");
5495                 emitcode ("cpl","a");
5496                 emitcode ("add", "a,#1");
5497                 emitcode ("xch", "a,b");
5498                 emitcode ("cpl", "a"); // msb
5499                 emitcode ("addc","a,#0");
5500                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5501                 emitcode ("setb","F0");
5502                 emitLabel (lbl);
5503                 emitcode ("mov","ma,b");
5504                 emitcode ("mov","ma,a");
5505         } else {
5506                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5507                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5508         }
5509         /* wait for multiplication to finish */
5510         lbl = newiTempLabel(NULL);
5511         emitLabel (lbl);
5512         emitcode("mov","a,mcnt1");
5513         emitcode("anl","a,#!constbyte",0x80);
5514         emitcode("jnz","!tlabel",lbl->key+100);
5515
5516         freeAsmop (left, NULL, ic, TRUE);
5517         freeAsmop (right, NULL, ic,TRUE);
5518         aopOp(result, ic, TRUE, FALSE);
5519
5520         /* if unsigned then simple */
5521         if (umult) {
5522                 emitcode ("mov","a,ma");
5523                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5524                 emitcode ("mov","a,ma");
5525                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5526                 aopPut(result,"ma",1);
5527                 aopPut(result,"ma",0);
5528         } else {
5529                 emitcode("push","ma");
5530                 emitcode("push","ma");
5531                 emitcode("push","ma");
5532                 MOVA("ma");
5533                 /* negate result if needed */
5534                 lbl = newiTempLabel(NULL);
5535                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5536                 emitcode("cpl","a");
5537                 emitcode("add","a,#1");
5538                 emitLabel (lbl);
5539                 if (AOP_TYPE(result) == AOP_ACC)
5540                 {
5541                     D (emitcode(";", "ACC special case."));
5542                     /* We know result is the only live aop, and
5543                      * it's obviously not a DPTR2, so AP is available.
5544                      */
5545                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5546                 }
5547                 else
5548                 {
5549                     aopPut(result,"a",0);
5550                 }
5551
5552                 emitcode("pop","acc");
5553                 lbl = newiTempLabel(NULL);
5554                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5555                 emitcode("cpl","a");
5556                 emitcode("addc","a,#0");
5557                 emitLabel (lbl);
5558                 aopPut(result,"a",1);
5559                 emitcode("pop","acc");
5560                 if (AOP_SIZE(result) >= 3) {
5561                         lbl = newiTempLabel(NULL);
5562                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5563                         emitcode("cpl","a");
5564                         emitcode("addc","a,#0");
5565                         emitLabel (lbl);
5566                         aopPut(result,"a",2);
5567                 }
5568                 emitcode("pop","acc");
5569                 if (AOP_SIZE(result) >= 4) {
5570                         lbl = newiTempLabel(NULL);
5571                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5572                         emitcode("cpl","a");
5573                         emitcode("addc","a,#0");
5574                         emitLabel (lbl);
5575                         aopPut(result,"a",3);
5576                 }
5577                 if (AOP_TYPE(result) == AOP_ACC)
5578                 {
5579                     /* We stashed the result away above. */
5580                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5581                 }
5582
5583         }
5584         freeAsmop (result, NULL, ic, TRUE);
5585
5586         /* restore EA bit in F1 */
5587         lbl = newiTempLabel(NULL);
5588         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5589         emitcode ("setb","EA");
5590         emitLabel (lbl);
5591         return ;
5592 }
5593
5594 /*-----------------------------------------------------------------*/
5595 /* genMult - generates code for multiplication                     */
5596 /*-----------------------------------------------------------------*/
5597 static void
5598 genMult (iCode * ic)
5599 {
5600   operand *left = IC_LEFT (ic);
5601   operand *right = IC_RIGHT (ic);
5602   operand *result = IC_RESULT (ic);
5603
5604   D (emitcode (";", "genMult"));
5605
5606   /* assign the asmops */
5607   AOP_OP_2 (ic);
5608
5609   /* special cases first */
5610   /* both are bits */
5611   if (AOP_TYPE (left) == AOP_CRY &&
5612       AOP_TYPE (right) == AOP_CRY)
5613     {
5614       genMultbits (left, right, result, ic);
5615       goto release;
5616     }
5617
5618   /* if both are of size == 1 */
5619   if (AOP_SIZE (left) == 1 &&
5620       AOP_SIZE (right) == 1)
5621     {
5622       genMultOneByte (left, right, result, ic);
5623       goto release;
5624     }
5625
5626   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5627           /* use the ds390 ARITHMETIC accel UNIT */
5628           genMultTwoByte (left, right, result, ic);
5629           return ;
5630   }
5631   /* should have been converted to function call */
5632   assert (0);
5633
5634 release:
5635   freeAsmop (result, NULL, ic, TRUE);
5636   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5637   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5638 }
5639
5640 /*-----------------------------------------------------------------*/
5641 /* genDivbits :- division of bits                                  */
5642 /*-----------------------------------------------------------------*/
5643 static void
5644 genDivbits (operand * left,
5645             operand * right,
5646             operand * result,
5647             iCode   * ic)
5648 {
5649   char *l;
5650   bool pushedB;
5651
5652   D(emitcode (";", "genDivbits"));
5653
5654   pushedB = pushB ();
5655
5656   /* the result must be bit */
5657   LOAD_AB_FOR_DIV (left, right, l);
5658   emitcode ("div", "ab");
5659   emitcode ("rrc", "a");
5660   aopOp(result, ic, TRUE, FALSE);
5661
5662   popB (pushedB);
5663
5664   aopPut (result, "c", 0);
5665 }
5666
5667 /*-----------------------------------------------------------------*/
5668 /* genDivOneByte : 8 bit division                                  */
5669 /*-----------------------------------------------------------------*/
5670 static void
5671 genDivOneByte (operand * left,
5672                operand * right,
5673                operand * result,
5674                iCode   * ic)
5675 {
5676   bool lUnsigned, rUnsigned, pushedB;
5677   bool runtimeSign, compiletimeSign;
5678   char *l;
5679   symbol *lbl;
5680   int size, offset;
5681
5682   D(emitcode (";", "genDivOneByte"));
5683
5684   offset = 1;
5685   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5686   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5687
5688   pushedB = pushB ();
5689
5690   /* signed or unsigned */
5691   if (lUnsigned && rUnsigned)
5692     {
5693       /* unsigned is easy */
5694       LOAD_AB_FOR_DIV (left, right, l);
5695       emitcode ("div", "ab");
5696
5697       _G.accInUse++;
5698       aopOp (result, ic, TRUE, FALSE);
5699       aopPut (result, "a", 0);
5700       _G.accInUse--;
5701
5702       size = AOP_SIZE (result) - 1;
5703
5704       while (size--)
5705         aopPut (result, zero, offset++);
5706
5707       popB (pushedB);
5708       return;
5709     }
5710
5711   /* signed is a little bit more difficult */
5712
5713   /* now sign adjust for both left & right */
5714
5715   /* let's see what's needed: */
5716   /* apply negative sign during runtime */
5717   runtimeSign = FALSE;
5718   /* negative sign from literals */
5719   compiletimeSign = FALSE;
5720
5721   if (!lUnsigned)
5722     {
5723       if (AOP_TYPE(left) == AOP_LIT)
5724         {
5725           /* signed literal */
5726           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5727           if (val < 0)
5728             compiletimeSign = TRUE;
5729         }
5730       else
5731         /* signed but not literal */
5732         runtimeSign = TRUE;
5733     }
5734
5735   if (!rUnsigned)
5736     {
5737       if (AOP_TYPE(right) == AOP_LIT)
5738         {
5739           /* signed literal */
5740           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5741           if (val < 0)
5742             compiletimeSign ^= TRUE;
5743         }
5744       else
5745         /* signed but not literal */
5746         runtimeSign = TRUE;
5747     }
5748
5749   /* initialize F0, which stores the runtime sign */
5750   if (runtimeSign)
5751     {
5752       if (compiletimeSign)
5753         emitcode ("setb", "F0"); /* set sign flag */
5754       else
5755         emitcode ("clr", "F0"); /* reset sign flag */
5756     }
5757
5758   /* save the signs of the operands */
5759   if (AOP_TYPE(right) == AOP_LIT)
5760     {
5761       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5762
5763       if (!rUnsigned && val < 0)
5764         emitcode ("mov", "b,#0x%02x", -val);
5765       else
5766         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5767     }
5768   else /* ! literal */
5769     {
5770       if (rUnsigned)
5771         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5772       else
5773         {
5774           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5775           lbl = newiTempLabel (NULL);
5776           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5777           emitcode ("cpl", "F0"); /* complement sign flag */
5778           emitcode ("cpl", "a");  /* 2's complement */
5779           emitcode ("inc", "a");
5780           emitLabel (lbl);
5781           emitcode ("mov", "b,a");
5782         }
5783     }
5784
5785   if (AOP_TYPE(left) == AOP_LIT)
5786     {
5787       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5788
5789       if (!lUnsigned && val < 0)
5790         emitcode ("mov", "a,#0x%02x", -val);
5791       else
5792         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5793     }
5794   else /* ! literal */
5795     {
5796       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5797
5798       if (!lUnsigned)
5799         {
5800           lbl = newiTempLabel (NULL);
5801           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5802           emitcode ("cpl", "F0"); /* complement sign flag */
5803           emitcode ("cpl", "a");  /* 2's complement */
5804           emitcode ("inc", "a");
5805           emitLabel (lbl);
5806         }
5807     }
5808
5809   /* now the division */
5810   emitcode ("nop", "; workaround for DS80C390 div bug.");
5811   emitcode ("div", "ab");
5812
5813   if (runtimeSign || compiletimeSign)
5814     {
5815       lbl = newiTempLabel (NULL);
5816       if (runtimeSign)
5817         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5818       emitcode ("cpl", "a"); /* lsb 2's complement */
5819       emitcode ("inc", "a");
5820       emitLabel (lbl);
5821
5822       _G.accInUse++;
5823       aopOp (result, ic, TRUE, FALSE);
5824       size = AOP_SIZE (result) - 1;
5825
5826       if (size > 0)
5827         {
5828           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5829              then the result will be in b, a */
5830           emitcode ("mov", "b,a"); /* 1 */
5831           /* msb is 0x00 or 0xff depending on the sign */
5832           if (runtimeSign)
5833             {
5834               emitcode ("mov",  "c,F0");
5835               emitcode ("subb", "a,acc");
5836               emitcode ("xch",  "a,b"); /* 2 */
5837               while (size--)
5838                 aopPut (result, "b", offset++); /* write msb's */
5839             }
5840           else /* compiletimeSign */
5841             while (size--)
5842               aopPut (result, "#0xff", offset++); /* write msb's */
5843         }
5844       aopPut (result, "a", 0); /* 3: write lsb */
5845     }
5846   else
5847     {
5848       _G.accInUse++;
5849       aopOp(result, ic, TRUE, FALSE);
5850       size = AOP_SIZE (result) - 1;
5851
5852       aopPut (result, "a", 0);
5853       while (size--)
5854         aopPut (result, zero, offset++);
5855     }
5856   _G.accInUse--;
5857   popB (pushedB);
5858 }
5859
5860 /*-----------------------------------------------------------------*/
5861 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5862 /*-----------------------------------------------------------------*/
5863 static void genDivTwoByte (operand *left, operand *right,
5864                             operand *result, iCode *ic)
5865 {
5866         sym_link *retype = getSpec(operandType(right));
5867         sym_link *letype = getSpec(operandType(left));
5868         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5869         symbol *lbl;
5870
5871         /* save EA bit in F1 */
5872         lbl = newiTempLabel(NULL);
5873         emitcode ("setb","F1");
5874         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5875         emitcode ("clr","F1");
5876         emitLabel (lbl);
5877
5878         /* load up MA with left */
5879         if (!umult) {
5880                 emitcode("clr","F0");
5881                 lbl = newiTempLabel(NULL);
5882                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5883                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5884                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5885                 emitcode ("xch", "a,b");
5886                 emitcode ("cpl","a");
5887                 emitcode ("add", "a,#1");
5888                 emitcode ("xch", "a,b");
5889                 emitcode ("cpl", "a"); // msb
5890                 emitcode ("addc","a,#0");
5891                 emitcode ("setb","F0");
5892                 emitLabel (lbl);
5893                 emitcode ("mov","ma,b");
5894                 emitcode ("mov","ma,a");
5895         } else {
5896                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5897                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5898         }
5899
5900         /* load up MB with right */
5901         if (!umult) {
5902                 if (AOP_TYPE(right) == AOP_LIT) {
5903                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5904                         if (val < 0) {
5905                                 lbl = newiTempLabel(NULL);
5906                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5907                                 emitcode("setb","F0");
5908                                 emitLabel (lbl);
5909                                 val = -val;
5910                         }
5911                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5912                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5913                 } else {
5914                         lbl = newiTempLabel(NULL);
5915                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5916                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5917                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5918                         emitcode ("xch", "a,b");
5919                         emitcode ("cpl","a");
5920                         emitcode ("add", "a,#1");
5921                         emitcode ("xch", "a,b");
5922                         emitcode ("cpl", "a"); // msb
5923                         emitcode ("addc", "a,#0");
5924                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5925                         emitcode ("setb","F0");
5926                         emitLabel (lbl);
5927                         emitcode ("mov","mb,b");
5928                         emitcode ("mov","mb,a");
5929                 }
5930         } else {
5931                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5932                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5933         }
5934
5935         /* wait for multiplication to finish */
5936         lbl = newiTempLabel(NULL);
5937         emitLabel (lbl);
5938         emitcode("mov","a,mcnt1");
5939         emitcode("anl","a,#!constbyte",0x80);
5940         emitcode("jnz","!tlabel",lbl->key+100);
5941
5942         freeAsmop (left, NULL, ic, TRUE);
5943         freeAsmop (right, NULL, ic,TRUE);
5944         aopOp(result, ic, TRUE, FALSE);
5945
5946         /* if unsigned then simple */
5947         if (umult) {
5948                 aopPut(result,"ma",1);
5949                 aopPut(result,"ma",0);
5950         } else {
5951                 emitcode("push","ma");
5952                 MOVA("ma");
5953                 /* negate result if needed */
5954                 lbl = newiTempLabel(NULL);
5955                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5956                 emitcode("cpl","a");
5957                 emitcode("add","a,#1");
5958                 emitLabel (lbl);
5959                 aopPut(result,"a",0);
5960                 emitcode("pop","acc");
5961                 lbl = newiTempLabel(NULL);
5962                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5963                 emitcode("cpl","a");
5964                 emitcode("addc","a,#0");
5965                 emitLabel (lbl);
5966                 aopPut(result,"a",1);
5967         }
5968         freeAsmop (result, NULL, ic, TRUE);
5969         /* restore EA bit in F1 */
5970         lbl = newiTempLabel(NULL);
5971         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5972         emitcode ("setb","EA");
5973         emitLabel (lbl);
5974         return ;
5975 }
5976
5977 /*-----------------------------------------------------------------*/
5978 /* genDiv - generates code for division                            */
5979 /*-----------------------------------------------------------------*/
5980 static void
5981 genDiv (iCode * ic)
5982 {
5983   operand *left = IC_LEFT (ic);
5984   operand *right = IC_RIGHT (ic);
5985   operand *result = IC_RESULT (ic);
5986
5987   D (emitcode (";", "genDiv"));
5988
5989   /* assign the amsops */
5990   AOP_OP_2 (ic);
5991
5992   /* special cases first */
5993   /* both are bits */
5994   if (AOP_TYPE (left) == AOP_CRY &&
5995       AOP_TYPE (right) == AOP_CRY)
5996     {
5997       genDivbits (left, right, result, ic);
5998       goto release;
5999     }
6000
6001   /* if both are of size == 1 */
6002   if (AOP_SIZE (left) == 1 &&
6003       AOP_SIZE (right) == 1)
6004     {
6005       genDivOneByte (left, right, result, ic);
6006       goto release;
6007     }
6008
6009   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6010           /* use the ds390 ARITHMETIC accel UNIT */
6011           genDivTwoByte (left, right, result, ic);
6012           return ;
6013   }
6014   /* should have been converted to function call */
6015   assert (0);
6016 release:
6017   freeAsmop (result, NULL, ic, TRUE);
6018   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6019   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6020 }
6021
6022 /*-----------------------------------------------------------------*/
6023 /* genModbits :- modulus of bits                                   */
6024 /*-----------------------------------------------------------------*/
6025 static void
6026 genModbits (operand * left,
6027             operand * right,
6028             operand * result,
6029             iCode   * ic)
6030 {
6031   char *l;
6032   bool pushedB;
6033
6034   D (emitcode (";", "genModbits"));
6035
6036   pushedB = pushB ();
6037
6038   /* the result must be bit */
6039   LOAD_AB_FOR_DIV (left, right, l);
6040   emitcode ("div", "ab");
6041   emitcode ("mov", "a,b");
6042   emitcode ("rrc", "a");
6043   aopOp(result, ic, TRUE, FALSE);
6044
6045   popB (pushedB);
6046
6047   aopPut (result, "c", 0);
6048 }
6049
6050 /*-----------------------------------------------------------------*/
6051 /* genModOneByte : 8 bit modulus                                   */
6052 /*-----------------------------------------------------------------*/
6053 static void
6054 genModOneByte (operand * left,
6055                operand * right,
6056                operand * result,
6057                iCode   * ic)
6058 {
6059   bool lUnsigned, rUnsigned, pushedB;
6060   bool runtimeSign, compiletimeSign;
6061   char *l;
6062   symbol *lbl;
6063   int size, offset;
6064
6065   D (emitcode (";", "genModOneByte"));
6066
6067   offset = 1;
6068   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6069   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6070
6071   pushedB = pushB ();
6072
6073   /* signed or unsigned */
6074   if (lUnsigned && rUnsigned)
6075     {
6076       /* unsigned is easy */
6077       LOAD_AB_FOR_DIV (left, right, l);
6078       emitcode ("div", "ab");
6079       aopOp (result, ic, TRUE, FALSE);
6080       aopPut (result, "b", 0);
6081
6082       for (size = AOP_SIZE (result) - 1; size--;)
6083         aopPut (result, zero, offset++);
6084
6085       popB (pushedB);
6086       return;
6087     }
6088
6089   /* signed is a little bit more difficult */
6090
6091   /* now sign adjust for both left & right */
6092
6093   /* modulus: sign of the right operand has no influence on the result! */
6094   if (AOP_TYPE(right) == AOP_LIT)
6095     {
6096       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
6097
6098       if (!rUnsigned && val < 0)
6099         emitcode ("mov", "b,#0x%02x", -val);
6100       else
6101         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6102     }
6103   else /* not literal */
6104     {
6105       if (rUnsigned)
6106         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6107       else
6108         {
6109           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6110           lbl = newiTempLabel (NULL);
6111           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6112           emitcode ("cpl", "a");  /* 2's complement */
6113           emitcode ("inc", "a");
6114           emitLabel (lbl);
6115           emitcode ("mov", "b,a");
6116         }
6117     }
6118
6119   /* let's see what's needed: */
6120   /* apply negative sign during runtime */
6121   runtimeSign = FALSE;
6122   /* negative sign from literals */
6123   compiletimeSign = FALSE;
6124
6125   /* sign adjust left side */
6126   if (AOP_TYPE(left) == AOP_LIT)
6127     {
6128       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
6129
6130       if (!lUnsigned && val < 0)
6131         {
6132           compiletimeSign = TRUE; /* set sign flag */
6133           emitcode ("mov", "a,#0x%02x", -val);
6134         }
6135       else
6136         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6137     }
6138   else /* ! literal */
6139     {
6140       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6141
6142       if (!lUnsigned)
6143         {
6144           runtimeSign = TRUE;
6145           emitcode ("clr", "F0"); /* clear sign flag */
6146
6147           lbl = newiTempLabel (NULL);
6148           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6149           emitcode ("setb", "F0"); /* set sign flag */
6150           emitcode ("cpl", "a");   /* 2's complement */
6151           emitcode ("inc", "a");
6152           emitLabel (lbl);
6153         }
6154     }
6155
6156   /* now the modulus */
6157   emitcode ("nop", "; workaround for DS80C390 div bug.");
6158   emitcode ("div", "ab");
6159
6160   if (runtimeSign || compiletimeSign)
6161     {
6162       emitcode ("mov", "a,b");
6163       lbl = newiTempLabel (NULL);
6164       if (runtimeSign)
6165         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6166       emitcode ("cpl", "a"); /* lsb 2's complement */
6167       emitcode ("inc", "a");
6168       emitLabel (lbl);
6169
6170       _G.accInUse++;
6171       aopOp (result, ic, TRUE, FALSE);
6172       size = AOP_SIZE (result) - 1;
6173
6174       if (size > 0)
6175         {
6176           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6177              then the result will be in b, a */
6178           emitcode ("mov", "b,a"); /* 1 */
6179           /* msb is 0x00 or 0xff depending on the sign */
6180           if (runtimeSign)
6181             {
6182               emitcode ("mov",  "c,F0");
6183               emitcode ("subb", "a,acc");
6184               emitcode ("xch",  "a,b"); /* 2 */
6185               while (size--)
6186                 aopPut (result, "b", offset++); /* write msb's */
6187             }
6188           else /* compiletimeSign */
6189             while (size--)
6190               aopPut (result, "#0xff", offset++); /* write msb's */
6191         }
6192       aopPut (result, "a", 0); /* 3: write lsb */
6193     }
6194   else
6195     {
6196       _G.accInUse++;
6197       aopOp(result, ic, TRUE, FALSE);
6198       size = AOP_SIZE (result) - 1;
6199
6200       aopPut (result, "b", 0);
6201       while (size--)
6202         aopPut (result, zero, offset++);
6203     }
6204   _G.accInUse--;
6205   popB (pushedB);
6206 }
6207
6208 /*-----------------------------------------------------------------*/
6209 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6210 /*-----------------------------------------------------------------*/
6211 static void genModTwoByte (operand *left, operand *right,
6212                             operand *result, iCode *ic)
6213 {
6214         sym_link *retype = getSpec(operandType(right));
6215         sym_link *letype = getSpec(operandType(left));
6216         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6217         symbol *lbl;
6218
6219         /* load up MA with left */
6220         /* save EA bit in F1 */
6221         lbl = newiTempLabel(NULL);
6222         emitcode ("setb","F1");
6223         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6224         emitcode ("clr","F1");
6225         emitLabel (lbl);
6226
6227         if (!umult) {
6228                 lbl = newiTempLabel(NULL);
6229                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6230                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6231                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6232                 emitcode ("xch", "a,b");
6233                 emitcode ("cpl","a");
6234                 emitcode ("add", "a,#1");
6235                 emitcode ("xch", "a,b");
6236                 emitcode ("cpl", "a"); // msb
6237                 emitcode ("addc","a,#0");
6238                 emitLabel (lbl);
6239                 emitcode ("mov","ma,b");
6240                 emitcode ("mov","ma,a");
6241         } else {
6242                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6243                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6244         }
6245
6246         /* load up MB with right */
6247         if (!umult) {
6248                 if (AOP_TYPE(right) == AOP_LIT) {
6249                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6250                         if (val < 0) {
6251                                 val = -val;
6252                         }
6253                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6254                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6255                 } else {
6256                         lbl = newiTempLabel(NULL);
6257                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6258                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6259                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6260                         emitcode ("xch", "a,b");
6261                         emitcode ("cpl","a");
6262                         emitcode ("add", "a,#1");
6263                         emitcode ("xch", "a,b");
6264                         emitcode ("cpl", "a"); // msb
6265                         emitcode ("addc", "a,#0");
6266                         emitLabel (lbl);
6267                         emitcode ("mov","mb,b");
6268                         emitcode ("mov","mb,a");
6269                 }
6270         } else {
6271                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6272                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6273         }
6274
6275         /* wait for multiplication to finish */
6276         lbl = newiTempLabel(NULL);
6277         emitLabel (lbl);
6278         emitcode("mov","a,mcnt1");
6279         emitcode("anl","a,#!constbyte",0x80);
6280         emitcode("jnz","!tlabel",lbl->key+100);
6281
6282         freeAsmop (left, NULL, ic, TRUE);
6283         freeAsmop (right, NULL, ic,TRUE);
6284         aopOp(result, ic, TRUE, FALSE);
6285
6286         aopPut(result,"mb",1);
6287         aopPut(result,"mb",0);
6288         freeAsmop (result, NULL, ic, TRUE);
6289
6290         /* restore EA bit in F1 */
6291         lbl = newiTempLabel(NULL);
6292         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6293         emitcode ("setb","EA");
6294         emitLabel (lbl);
6295 }
6296
6297 /*-----------------------------------------------------------------*/
6298 /* genMod - generates code for division                            */
6299 /*-----------------------------------------------------------------*/
6300 static void
6301 genMod (iCode * ic)
6302 {
6303   operand *left = IC_LEFT (ic);
6304   operand *right = IC_RIGHT (ic);
6305   operand *result = IC_RESULT (ic);
6306
6307   D (emitcode (";", "genMod"));
6308
6309   /* assign the asmops */
6310   AOP_OP_2 (ic);
6311
6312   /* special cases first */
6313   /* both are bits */
6314   if (AOP_TYPE (left) == AOP_CRY &&
6315       AOP_TYPE (right) == AOP_CRY)
6316     {
6317       genModbits (left, right, result, ic);
6318       goto release;
6319     }
6320
6321   /* if both are of size == 1 */
6322   if (AOP_SIZE (left) == 1 &&
6323       AOP_SIZE (right) == 1)
6324     {
6325       genModOneByte (left, right, result, ic);
6326       goto release;
6327     }
6328
6329   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6330           /* use the ds390 ARITHMETIC accel UNIT */
6331           genModTwoByte (left, right, result, ic);
6332           return ;
6333   }
6334
6335   /* should have been converted to function call */
6336   assert (0);
6337
6338 release:
6339   freeAsmop (result, NULL, ic, TRUE);
6340   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6341   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6342 }
6343
6344 /*-----------------------------------------------------------------*/
6345 /* genIfxJump :- will create a jump depending on the ifx           */
6346 /*-----------------------------------------------------------------*/
6347 static void
6348 genIfxJump (iCode * ic, char *jval)
6349 {
6350   symbol *jlbl;
6351   symbol *tlbl = newiTempLabel (NULL);
6352   char *inst;
6353
6354   D (emitcode (";", "genIfxJump"));
6355
6356   /* if true label then we jump if condition
6357      supplied is true */
6358   if (IC_TRUE (ic))
6359     {
6360       jlbl = IC_TRUE (ic);
6361       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6362                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6363     }
6364   else
6365     {
6366       /* false label is present */
6367       jlbl = IC_FALSE (ic);
6368       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6369                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6370     }
6371   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6372     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6373   else
6374     emitcode (inst, "!tlabel", tlbl->key + 100);
6375   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6376   emitLabel (tlbl);
6377
6378   /* mark the icode as generated */
6379   ic->generated = 1;
6380 }
6381
6382 /*-----------------------------------------------------------------*/
6383 /* genCmp :- greater or less than comparison                       */
6384 /*-----------------------------------------------------------------*/
6385 static void
6386 genCmp (operand * left, operand * right,
6387         iCode * ic, iCode * ifx, int sign)
6388 {
6389   int size, offset = 0;
6390   unsigned long lit = 0L;
6391   operand *result;
6392
6393   D (emitcode (";", "genCmp"));
6394
6395   result = IC_RESULT (ic);
6396
6397   /* if left & right are bit variables */
6398   if (AOP_TYPE (left) == AOP_CRY &&
6399       AOP_TYPE (right) == AOP_CRY)
6400     {
6401       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6402       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6403     }
6404   else
6405     {
6406       /* subtract right from left if at the
6407          end the carry flag is set then we know that
6408          left is greater than right */
6409       size = max (AOP_SIZE (left), AOP_SIZE (right));
6410
6411       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6412       if ((size == 1) && !sign &&
6413           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6414         {
6415           symbol *lbl = newiTempLabel (NULL);
6416           emitcode ("cjne", "%s,%s,!tlabel",
6417                     aopGet (left, offset, FALSE, FALSE, NULL),
6418                     aopGet (right, offset, FALSE, FALSE, NULL),
6419                     lbl->key + 100);
6420           emitLabel (lbl);
6421         }
6422       else
6423         {
6424           if (AOP_TYPE (right) == AOP_LIT)
6425             {
6426               lit = ulFromVal (AOP (right)->aopu.aop_lit);
6427               /* optimize if(x < 0) or if(x >= 0) */
6428               if (lit == 0L)
6429                 {
6430                   if (!sign)
6431                     {
6432                       CLRC;
6433                     }
6434                   else
6435                     {
6436                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6437
6438                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6439                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6440
6441                       aopOp (result, ic, FALSE, FALSE);
6442
6443                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6444                         {
6445                           freeAsmop (result, NULL, ic, TRUE);
6446                           genIfxJump (ifx, "acc.7");
6447                           return;
6448                         }
6449                       else
6450                         {
6451                           emitcode ("rlc", "a");
6452                         }
6453                       goto release_freedLR;
6454                     }
6455                   goto release;
6456                 }
6457             }
6458           CLRC;
6459           while (size--)
6460             {
6461               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6462               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6463               // emitcode (";", "genCmp #2");
6464               if (sign && (size == 0))
6465                 {
6466                   // emitcode (";", "genCmp #3");
6467                   emitcode ("xrl", "a,#!constbyte",0x80);
6468                   if (AOP_TYPE (right) == AOP_LIT)
6469                     {
6470                       unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
6471                       // emitcode (";", "genCmp #3.1");
6472                       emitcode ("subb", "a,#!constbyte",
6473                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6474                     }
6475                   else
6476                     {
6477                       // emitcode (";", "genCmp #3.2");
6478                       saveAccWarn = 0;
6479                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6480                       saveAccWarn = DEFAULT_ACC_WARNING;
6481                       emitcode ("xrl", "b,#!constbyte",0x80);
6482                       emitcode ("subb", "a,b");
6483                     }
6484                 }
6485               else
6486                 {
6487                   const char *s;
6488
6489                   // emitcode (";", "genCmp #4");
6490                   saveAccWarn = 0;
6491                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6492                   saveAccWarn = DEFAULT_ACC_WARNING;
6493
6494                   emitcode ("subb", "a,%s", s);
6495                 }
6496             }
6497         }
6498     }
6499
6500 release:
6501 /* Don't need the left & right operands any more; do need the result. */
6502   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6503   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6504
6505   aopOp (result, ic, FALSE, FALSE);
6506
6507 release_freedLR:
6508
6509   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6510     {
6511       outBitC (result);
6512     }
6513   else
6514     {
6515       /* if the result is used in the next
6516          ifx conditional branch then generate
6517          code a little differently */
6518       if (ifx)
6519         {
6520           genIfxJump (ifx, "c");
6521         }
6522       else
6523         {
6524           outBitC (result);
6525         }
6526       /* leave the result in acc */
6527     }
6528   freeAsmop (result, NULL, ic, TRUE);
6529 }
6530
6531 /*-----------------------------------------------------------------*/
6532 /* genCmpGt :- greater than comparison                             */
6533 /*-----------------------------------------------------------------*/
6534 static void
6535 genCmpGt (iCode * ic, iCode * ifx)
6536 {
6537   operand *left, *right;
6538   sym_link *letype, *retype;
6539   int sign;
6540
6541   D (emitcode (";", "genCmpGt"));
6542
6543   left = IC_LEFT (ic);
6544   right = IC_RIGHT (ic);
6545
6546   letype = getSpec (operandType (left));
6547   retype = getSpec (operandType (right));
6548   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6549
6550   /* assign the left & right amsops */
6551   AOP_OP_2 (ic);
6552
6553   genCmp (right, left, ic, ifx, sign);
6554 }
6555
6556 /*-----------------------------------------------------------------*/
6557 /* genCmpLt - less than comparisons                                */
6558 /*-----------------------------------------------------------------*/
6559 static void
6560 genCmpLt (iCode * ic, iCode * ifx)
6561 {
6562   operand *left, *right;
6563   sym_link *letype, *retype;
6564   int sign;
6565
6566   D (emitcode (";", "genCmpLt"));
6567
6568   left = IC_LEFT (ic);
6569   right = IC_RIGHT (ic);
6570
6571   letype = getSpec (operandType (left));
6572   retype = getSpec (operandType (right));
6573   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6574
6575   /* assign the left & right amsops */
6576   AOP_OP_2 (ic);
6577
6578   genCmp (left, right, ic, ifx, sign);
6579 }
6580
6581 /*-----------------------------------------------------------------*/
6582 /* gencjneshort - compare and jump if not equal                    */
6583 /*-----------------------------------------------------------------*/
6584 static void
6585 gencjneshort (operand * left, operand * right, symbol * lbl)
6586 {
6587   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6588   int offset = 0;
6589   unsigned long lit = 0L;
6590
6591   D (emitcode (";", "gencjneshort"));
6592
6593   /* if the left side is a literal or
6594      if the right is in a pointer register and left
6595      is not */
6596   if ((AOP_TYPE (left) == AOP_LIT) ||
6597       (AOP_TYPE (left) == AOP_IMMD) ||
6598       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6599     {
6600       operand *t = right;
6601       right = left;
6602       left = t;
6603     }
6604
6605   if (AOP_TYPE (right) == AOP_LIT)
6606     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6607
6608   if (opIsGptr (left) || opIsGptr (right))
6609     {
6610       /* We are comparing a generic pointer to something.
6611        * Exclude the generic type byte from the comparison.
6612        */
6613       size--;
6614       D (emitcode (";", "cjneshort: generic ptr special case."););
6615     }
6616
6617
6618   /* if the right side is a literal then anything goes */
6619   if (AOP_TYPE (right) == AOP_LIT &&
6620       AOP_TYPE (left) != AOP_DIR)
6621     {
6622       while (size--)
6623         {
6624           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6625           emitcode ("cjne", "a,%s,!tlabel",
6626                     aopGet (right, offset, FALSE, FALSE, NULL),
6627                     lbl->key + 100);
6628           offset++;
6629         }
6630     }
6631
6632   /* if the right side is in a register or in direct space or
6633      if the left is a pointer register & right is not */
6634   else if (AOP_TYPE (right) == AOP_REG ||
6635            AOP_TYPE (right) == AOP_DIR ||
6636            AOP_TYPE (right) == AOP_LIT ||
6637            AOP_TYPE (right) == AOP_IMMD ||
6638            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6639            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6640     {
6641       while (size--)
6642         {
6643           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6644           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6645               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6646             emitcode ("jnz", "!tlabel", lbl->key + 100);
6647           else
6648             emitcode ("cjne", "a,%s,!tlabel",
6649                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6650                       lbl->key + 100);
6651           offset++;
6652         }
6653     }
6654   else
6655     {
6656       /* right is a pointer reg need both a & b */
6657       while (size--)
6658         {
6659           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6660           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6661           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6662           offset++;
6663         }
6664     }
6665 }
6666
6667 /*-----------------------------------------------------------------*/
6668 /* gencjne - compare and jump if not equal                         */
6669 /*-----------------------------------------------------------------*/
6670 static void
6671 gencjne (operand * left, operand * right, symbol * lbl)
6672 {
6673   symbol *tlbl = newiTempLabel (NULL);
6674
6675   D (emitcode (";", "gencjne"));
6676
6677   gencjneshort (left, right, lbl);
6678
6679   emitcode ("mov", "a,%s", one);
6680   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6681   emitLabel (lbl);
6682   emitcode ("clr", "a");
6683   emitLabel (tlbl);
6684 }
6685
6686 /*-----------------------------------------------------------------*/
6687 /* genCmpEq - generates code for equal to                          */
6688 /*-----------------------------------------------------------------*/
6689 static void
6690 genCmpEq (iCode * ic, iCode * ifx)
6691 {
6692   operand *left, *right, *result;
6693
6694   D (emitcode (";", "genCmpEq"));
6695
6696   AOP_OP_2 (ic);
6697   AOP_SET_LOCALS (ic);
6698
6699   /* if literal, literal on the right or
6700      if the right is in a pointer register and left
6701      is not */
6702   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6703       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6704     {
6705       operand *t = IC_RIGHT (ic);
6706       IC_RIGHT (ic) = IC_LEFT (ic);
6707       IC_LEFT (ic) = t;
6708     }
6709
6710   if (ifx &&                    /* !AOP_SIZE(result) */
6711       OP_SYMBOL (result) &&
6712       OP_SYMBOL (result)->regType == REG_CND)
6713     {
6714       symbol *tlbl;
6715       /* if they are both bit variables */
6716       if (AOP_TYPE (left) == AOP_CRY &&
6717           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6718         {
6719           if (AOP_TYPE (right) == AOP_LIT)
6720             {
6721               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6722               if (lit == 0L)
6723                 {
6724                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6725                   emitcode ("cpl", "c");
6726                 }
6727               else if (lit == 1L)
6728                 {
6729                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6730                 }
6731               else
6732                 {
6733                   emitcode ("clr", "c");
6734                 }
6735               /* AOP_TYPE(right) == AOP_CRY */
6736             }
6737           else
6738             {
6739               symbol *lbl = newiTempLabel (NULL);
6740               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6741               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6742               emitcode ("cpl", "c");
6743               emitLabel (lbl);
6744             }
6745           /* if true label then we jump if condition
6746              supplied is true */
6747           tlbl = newiTempLabel (NULL);
6748           if (IC_TRUE (ifx))
6749             {
6750               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6751               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6752             }
6753           else
6754             {
6755               emitcode ("jc", "!tlabel", tlbl->key + 100);
6756               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6757             }
6758           emitLabel (tlbl);
6759         }
6760       else
6761         {
6762           tlbl = newiTempLabel (NULL);
6763           gencjneshort (left, right, tlbl);
6764           if (IC_TRUE (ifx))
6765             {
6766               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6767               emitLabel (tlbl);
6768             }
6769           else
6770             {
6771               symbol *lbl = newiTempLabel (NULL);
6772               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6773               emitLabel (tlbl);
6774               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6775               emitLabel (lbl);
6776             }
6777         }
6778       /* mark the icode as generated */
6779       ifx->generated = 1;
6780
6781       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6782       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6783       return;
6784     }
6785
6786   /* if they are both bit variables */
6787   if (AOP_TYPE (left) == AOP_CRY &&
6788       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6789     {
6790       if (AOP_TYPE (right) == AOP_LIT)
6791         {
6792           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6793           if (lit == 0L)
6794             {
6795               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6796               emitcode ("cpl", "c");
6797             }
6798           else if (lit == 1L)
6799             {
6800               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6801             }
6802           else
6803             {
6804               emitcode ("clr", "c");
6805             }
6806           /* AOP_TYPE(right) == AOP_CRY */
6807         }
6808       else
6809         {
6810           symbol *lbl = newiTempLabel (NULL);
6811           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6812           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6813           emitcode ("cpl", "c");
6814           emitLabel (lbl);
6815         }
6816
6817       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6818       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6819
6820       aopOp (result, ic, TRUE, FALSE);
6821
6822       /* c = 1 if egal */
6823       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6824         {
6825           outBitC (result);
6826           goto release;
6827         }
6828       if (ifx)
6829         {
6830           genIfxJump (ifx, "c");
6831           goto release;
6832         }
6833       /* if the result is used in an arithmetic operation
6834          then put the result in place */
6835       outBitC (result);
6836     }
6837   else
6838     {
6839       gencjne (left, right, newiTempLabel (NULL));
6840
6841       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6842       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6843
6844       aopOp (result, ic, TRUE, FALSE);
6845
6846       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6847         {
6848           aopPut (result, "a", 0);
6849           goto release;
6850         }
6851       if (ifx)
6852         {
6853           genIfxJump (ifx, "a");
6854           goto release;
6855         }
6856       /* if the result is used in an arithmetic operation
6857          then put the result in place */
6858       if (AOP_TYPE (result) != AOP_CRY)
6859         outAcc (result);
6860       /* leave the result in acc */
6861     }
6862
6863 release:
6864   freeAsmop (result, NULL, ic, TRUE);
6865 }
6866
6867 /*-----------------------------------------------------------------*/
6868 /* ifxForOp - returns the icode containing the ifx for operand     */
6869 /*-----------------------------------------------------------------*/
6870 static iCode *
6871 ifxForOp (operand * op, iCode * ic)
6872 {
6873   /* if true symbol then needs to be assigned */
6874   if (IS_TRUE_SYMOP (op))
6875     return NULL;
6876
6877   /* if this has register type condition and
6878      the next instruction is ifx with the same operand
6879      and live to of the operand is upto the ifx only then */
6880   if (ic->next &&
6881       ic->next->op == IFX &&
6882       IC_COND (ic->next)->key == op->key &&
6883       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6884     return ic->next;
6885
6886   return NULL;
6887 }
6888
6889 /*-----------------------------------------------------------------*/
6890 /* hasInc - operand is incremented before any other use            */
6891 /*-----------------------------------------------------------------*/
6892 static iCode *
6893 hasInc (operand *op, iCode *ic, int osize)
6894 {
6895   sym_link *type = operandType(op);
6896   sym_link *retype = getSpec (type);
6897   iCode *lic = ic->next;
6898   int isize ;
6899
6900   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6901   if (!IS_SYMOP(op)) return NULL;
6902
6903   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6904   if (IS_AGGREGATE(type->next)) return NULL;
6905   if (osize != (isize = getSize(type->next))) return NULL;
6906
6907   while (lic) {
6908       /* if operand of the form op = op + <sizeof *op> */
6909       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6910           isOperandEqual(IC_RESULT(lic),op) &&
6911           isOperandLiteral(IC_RIGHT(lic)) &&
6912           operandLitValue(IC_RIGHT(lic)) == isize) {
6913           return lic;
6914       }
6915       /* if the operand used or deffed */
6916       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6917           return NULL;
6918       }
6919       /* if GOTO or IFX */
6920       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6921       lic = lic->next;
6922   }
6923   return NULL;
6924 }
6925
6926 /*-----------------------------------------------------------------*/
6927 /* genAndOp - for && operation                                     */
6928 /*-----------------------------------------------------------------*/
6929 static void
6930 genAndOp (iCode * ic)
6931 {
6932   operand *left, *right, *result;
6933   symbol *tlbl;
6934
6935   D (emitcode (";", "genAndOp"));
6936
6937   /* note here that && operations that are in an
6938      if statement are taken away by backPatchLabels
6939      only those used in arthmetic operations remain */
6940   AOP_OP_2 (ic);
6941   AOP_SET_LOCALS (ic);
6942
6943   /* if both are bit variables */
6944   if (AOP_TYPE (left) == AOP_CRY &&
6945       AOP_TYPE (right) == AOP_CRY)
6946     {
6947       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6948       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6949       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6950       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6951
6952       aopOp (result,ic,FALSE, FALSE);
6953       outBitC (result);
6954     }
6955   else
6956     {
6957       tlbl = newiTempLabel (NULL);
6958       toBoolean (left);
6959       emitcode ("jz", "!tlabel", tlbl->key + 100);
6960       toBoolean (right);
6961       emitLabel (tlbl);
6962       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6963       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6964
6965       aopOp (result,ic,FALSE, FALSE);
6966       outBitAcc (result);
6967     }
6968
6969     freeAsmop (result, NULL, ic, TRUE);
6970 }
6971
6972
6973 /*-----------------------------------------------------------------*/
6974 /* genOrOp - for || operation                                      */
6975 /*-----------------------------------------------------------------*/
6976 static void
6977 genOrOp (iCode * ic)
6978 {
6979   operand *left, *right, *result;
6980   symbol *tlbl;
6981
6982   D (emitcode (";", "genOrOp"));
6983
6984   /* note here that || operations that are in an
6985      if statement are taken away by backPatchLabels
6986      only those used in arthmetic operations remain */
6987   AOP_OP_2 (ic);
6988   AOP_SET_LOCALS (ic);
6989
6990   /* if both are bit variables */
6991   if (AOP_TYPE (left) == AOP_CRY &&
6992       AOP_TYPE (right) == AOP_CRY)
6993     {
6994       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6995       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6996       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6997       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6998
6999       aopOp (result,ic,FALSE, FALSE);
7000
7001       outBitC (result);
7002     }
7003   else
7004     {
7005       tlbl = newiTempLabel (NULL);
7006       toBoolean (left);
7007       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7008       toBoolean (right);
7009       emitLabel (tlbl);
7010       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7011       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7012
7013       aopOp (result,ic,FALSE, FALSE);
7014
7015       outBitAcc (result);
7016     }
7017
7018   freeAsmop (result, NULL, ic, TRUE);
7019 }
7020
7021 /*-----------------------------------------------------------------*/
7022 /* isLiteralBit - test if lit == 2^n                               */
7023 /*-----------------------------------------------------------------*/
7024 static int
7025 isLiteralBit (unsigned long lit)
7026 {
7027   unsigned long pw[32] =
7028   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7029    0x100L, 0x200L, 0x400L, 0x800L,
7030    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7031    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7032    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7033    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7034    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7035   int idx;
7036
7037   for (idx = 0; idx < 32; idx++)
7038     if (lit == pw[idx])
7039       return idx + 1;
7040   return 0;
7041 }
7042
7043 /*-----------------------------------------------------------------*/
7044 /* continueIfTrue -                                                */
7045 /*-----------------------------------------------------------------*/
7046 static void
7047 continueIfTrue (iCode * ic)
7048 {
7049   if (IC_TRUE (ic))
7050     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7051   ic->generated = 1;
7052 }
7053
7054 /*-----------------------------------------------------------------*/
7055 /* jmpIfTrue -                                                     */
7056 /*-----------------------------------------------------------------*/
7057 static void
7058 jumpIfTrue (iCode * ic)
7059 {
7060   if (!IC_TRUE (ic))
7061     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7062   ic->generated = 1;
7063 }
7064
7065 /*-----------------------------------------------------------------*/
7066 /* jmpTrueOrFalse -                                                */
7067 /*-----------------------------------------------------------------*/
7068 static void
7069 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7070 {
7071   // ugly but optimized by peephole
7072   if (IC_TRUE (ic))
7073     {
7074       symbol *nlbl = newiTempLabel (NULL);
7075       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7076       emitLabel (tlbl);
7077       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7078       emitLabel (nlbl);
7079     }
7080   else
7081     {
7082       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7083       emitLabel (tlbl);
7084     }
7085   ic->generated = 1;
7086 }
7087
7088 // Generate code to perform a bit-wise logic operation
7089 // on two operands in far space (assumed to already have been
7090 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7091 // in far space. This requires pushing the result on the stack
7092 // then popping it into the result.
7093 static void
7094 genFarFarLogicOp(iCode *ic, char *logicOp)
7095 {
7096       int size, resultSize, compSize;
7097       int offset = 0;
7098
7099       TR_AP("#5");
7100       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7101       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7102                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7103
7104       _startLazyDPSEvaluation();
7105       for (size = compSize; (size--); offset++)
7106       {
7107           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7108           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7109           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7110
7111           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7112           emitcode ("push", "acc");
7113       }
7114       _endLazyDPSEvaluation();
7115
7116       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7117       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7118       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7119
7120       resultSize = AOP_SIZE(IC_RESULT(ic));
7121
7122       ADJUST_PUSHED_RESULT(compSize, resultSize);
7123
7124       _startLazyDPSEvaluation();
7125       while (compSize--)
7126       {
7127           emitcode ("pop", "acc");
7128           aopPut (IC_RESULT (ic), "a", compSize);
7129       }
7130       _endLazyDPSEvaluation();
7131       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7132 }
7133
7134
7135 /*-----------------------------------------------------------------*/
7136 /* genAnd  - code for and                                          */
7137 /*-----------------------------------------------------------------*/
7138 static void
7139 genAnd (iCode * ic, iCode * ifx)
7140 {
7141   operand *left, *right, *result;
7142   int size, offset = 0;
7143   unsigned long lit = 0L;
7144   int bytelit = 0;
7145   char buffer[10];
7146   bool pushResult;
7147
7148   D (emitcode (";", "genAnd"));
7149
7150   AOP_OP_3_NOFATAL (ic, pushResult);
7151   AOP_SET_LOCALS (ic);
7152
7153   if (pushResult)
7154   {
7155       genFarFarLogicOp(ic, "anl");
7156       return;
7157   }
7158
7159 #ifdef DEBUG_TYPE
7160   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7161             AOP_TYPE (result),
7162             AOP_TYPE (left), AOP_TYPE (right));
7163   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7164             AOP_SIZE (result),
7165             AOP_SIZE (left), AOP_SIZE (right));
7166 #endif
7167
7168   /* if left is a literal & right is not then exchange them */
7169   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7170 #ifdef LOGIC_OPS_BROKEN
7171     ||  AOP_NEEDSACC (left)
7172 #endif
7173     )
7174     {
7175       operand *tmp = right;
7176       right = left;
7177       left = tmp;
7178     }
7179
7180   /* if result = right then exchange left and right */
7181   if (sameRegs (AOP (result), AOP (right)))
7182     {
7183       operand *tmp = right;
7184       right = left;
7185       left = tmp;
7186     }
7187
7188   /* if right is bit then exchange them */
7189   if (AOP_TYPE (right) == AOP_CRY &&
7190       AOP_TYPE (left) != AOP_CRY)
7191     {
7192       operand *tmp = right;
7193       right = left;
7194       left = tmp;
7195     }
7196   if (AOP_TYPE (right) == AOP_LIT)
7197     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7198
7199   size = AOP_SIZE (result);
7200
7201   // if(bit & yy)
7202   // result = bit & yy;
7203   if (AOP_TYPE (left) == AOP_CRY)
7204     {
7205       // c = bit & literal;
7206       if (AOP_TYPE (right) == AOP_LIT)
7207         {
7208           if (lit & 1)
7209             {
7210               if (size && sameRegs (AOP (result), AOP (left)))
7211                 // no change
7212                 goto release;
7213               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7214             }
7215           else
7216             {
7217               // bit(result) = 0;
7218               if (size && (AOP_TYPE (result) == AOP_CRY))
7219                 {
7220                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7221                   goto release;
7222                 }
7223               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7224                 {
7225                   jumpIfTrue (ifx);
7226                   goto release;
7227                 }
7228               emitcode ("clr", "c");
7229             }
7230         }
7231       else
7232         {
7233           if (AOP_TYPE (right) == AOP_CRY)
7234             {
7235               // c = bit & bit;
7236               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7237               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7238             }
7239           else
7240             {
7241               // c = bit & val;
7242               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7243               // c = lsb
7244               emitcode ("rrc", "a");
7245               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7246             }
7247         }
7248       // bit = c
7249       // val = c
7250       if (size)
7251         outBitC (result);
7252       // if(bit & ...)
7253       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7254         genIfxJump (ifx, "c");
7255       goto release;
7256     }
7257
7258   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7259   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7260   if ((AOP_TYPE (right) == AOP_LIT) &&
7261       (AOP_TYPE (result) == AOP_CRY) &&
7262       (AOP_TYPE (left) != AOP_CRY))
7263     {
7264       int posbit = isLiteralBit (lit);
7265       /* left &  2^n */
7266       if (posbit)
7267         {
7268           posbit--;
7269           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7270           // bit = left & 2^n
7271           if (size)
7272             {
7273               switch (posbit & 0x07)
7274                 {
7275                   case 0: emitcode ("rrc", "a");
7276                           break;
7277                   case 7: emitcode ("rlc", "a");
7278                           break;
7279                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7280                           break;
7281                 }
7282             }
7283           // if(left &  2^n)
7284           else
7285             {
7286               if (ifx)
7287                 {
7288                   SNPRINTF (buffer, sizeof(buffer),
7289                             "acc.%d", posbit & 0x07);
7290                   genIfxJump (ifx, buffer);
7291                 }
7292               else
7293                 {
7294                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7295                 }
7296               goto release;
7297             }
7298         }
7299       else
7300         {
7301           symbol *tlbl = newiTempLabel (NULL);
7302           int sizel = AOP_SIZE (left);
7303           if (size)
7304             emitcode ("setb", "c");
7305           while (sizel--)
7306             {
7307               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7308                 {
7309                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7310                   // byte ==  2^n ?
7311                   if ((posbit = isLiteralBit (bytelit)) != 0)
7312                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7313                   else
7314                     {
7315                       if (bytelit != 0x0FFL)
7316                         emitcode ("anl", "a,%s",
7317                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7318                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7319                     }
7320                 }
7321               offset++;
7322             }
7323           // bit = left & literal
7324           if (size)
7325             {
7326               emitcode ("clr", "c");
7327               emitLabel (tlbl);
7328             }
7329           // if(left & literal)
7330           else
7331             {
7332               if (ifx)
7333                 jmpTrueOrFalse (ifx, tlbl);
7334               else
7335                 emitLabel (tlbl);
7336               goto release;
7337             }
7338         }
7339       outBitC (result);
7340       goto release;
7341     }
7342
7343   /* if left is same as result */
7344   if (sameRegs (AOP (result), AOP (left)))
7345     {
7346       for (; size--; offset++)
7347         {
7348           if (AOP_TYPE (right) == AOP_LIT)
7349             {
7350               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7351               if (bytelit == 0x0FF)
7352                 {
7353                   /* dummy read of volatile operand */
7354                   if (isOperandVolatile (left, FALSE))
7355                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7356                   else
7357                     continue;
7358                 }
7359               else if (bytelit == 0)
7360                 {
7361                   aopPut (result, zero, offset);
7362                 }
7363               else if (IS_AOP_PREG (result))
7364                 {
7365                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7366                   emitcode ("anl", "a,%s",
7367                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7368                   aopPut (result, "a", offset);
7369                 }
7370               else
7371                 emitcode ("anl", "%s,%s",
7372                           aopGet (left, offset, FALSE, TRUE, NULL),
7373                           aopGet (right, offset, FALSE, FALSE, NULL));
7374             }
7375           else
7376             {
7377               if (AOP_TYPE (left) == AOP_ACC)
7378                 {
7379                   if (offset)
7380                     emitcode("mov", "a,b");
7381                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7382                 }
7383               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7384                 {
7385                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7386                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7387                   emitcode ("anl", "a,b");
7388                   aopPut (result, "a", offset);
7389                 }
7390               else if (aopGetUsesAcc (left, offset))
7391                 {
7392                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7393                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7394                   aopPut (result, "a", offset);
7395                 }
7396               else
7397                 {
7398                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7399                   if (IS_AOP_PREG (result))
7400                     {
7401                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7402                       aopPut (result, "a", offset);
7403                     }
7404                   else
7405                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7406                 }
7407             }
7408         }
7409     }
7410   else
7411     {
7412       // left & result in different registers
7413       if (AOP_TYPE (result) == AOP_CRY)
7414         {
7415           // result = bit
7416           // if(size), result in bit
7417           // if(!size && ifx), conditional oper: if(left & right)
7418           symbol *tlbl = newiTempLabel (NULL);
7419           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7420           if (size)
7421             emitcode ("setb", "c");
7422           while (sizer--)
7423             {
7424               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7425                   && AOP_TYPE(left)==AOP_ACC)
7426                 {
7427                   if (offset)
7428                     emitcode("mov", "a,b");
7429                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7430                 }
7431               else if (AOP_TYPE(left)==AOP_ACC)
7432                 {
7433                   if (!offset)
7434                     {
7435                       bool pushedB = pushB ();
7436                       emitcode("mov", "b,a");
7437                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7438                       emitcode("anl", "a,b");
7439                       popB (pushedB);
7440                     }
7441                   else
7442                     {
7443                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7444                       emitcode("anl", "a,b");
7445                     }
7446                 }
7447               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7448                 {
7449                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7450                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7451                   emitcode ("anl", "a,b");
7452                 }
7453               else if (aopGetUsesAcc (left, offset))
7454                 {
7455                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7456                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7457                 }
7458               else
7459                 {
7460                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7461                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7462                 }
7463
7464               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7465               offset++;
7466             }
7467           if (size)
7468             {
7469               CLRC;
7470               emitLabel (tlbl);
7471               outBitC (result);
7472             }
7473           else if (ifx)
7474             jmpTrueOrFalse (ifx, tlbl);
7475           else
7476             emitLabel (tlbl);
7477         }
7478       else
7479         {
7480           for (; (size--); offset++)
7481             {
7482               // normal case
7483               // result = left & right
7484               if (AOP_TYPE (right) == AOP_LIT)
7485                 {
7486                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7487                   if (bytelit == 0x0FF)
7488                     {
7489                       aopPut (result,
7490                               aopGet (left, offset, FALSE, FALSE, NULL),
7491                               offset);
7492                       continue;
7493                     }
7494                   else if (bytelit == 0)
7495                     {
7496                       /* dummy read of volatile operand */
7497                       if (isOperandVolatile (left, FALSE))
7498                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7499                       aopPut (result, zero, offset);
7500                       continue;
7501                     }
7502                   else if (AOP_TYPE (left) == AOP_ACC)
7503                     {
7504                       if (!offset)
7505                         {
7506                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7507                           aopPut (result, "a", offset);
7508                           continue;
7509                         }
7510                       else
7511                         {
7512                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7513                           aopPut (result, "b", offset);
7514                           continue;
7515                         }
7516                     }
7517                 }
7518               // faster than result <- left, anl result,right
7519               // and better if result is SFR
7520               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7521                   && AOP_TYPE(left)==AOP_ACC)
7522                 {
7523                   if (offset)
7524                     emitcode("mov", "a,b");
7525                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7526                 }
7527               else if (AOP_TYPE(left)==AOP_ACC)
7528                 {
7529                   if (!offset)
7530                     {
7531                       bool pushedB = pushB ();
7532                       emitcode("mov", "b,a");
7533                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7534                       emitcode("anl", "a,b");
7535                       popB (pushedB);
7536                     }
7537                   else
7538                     {
7539                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7540                       emitcode("anl", "a,b");
7541                     }
7542                 }
7543               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7544                 {
7545                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7546                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7547                   emitcode ("anl", "a,b");
7548                 }
7549               else if (aopGetUsesAcc (left, offset))
7550                 {
7551                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7552                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7553                 }
7554               else
7555                 {
7556                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7557                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7558                 }
7559               aopPut (result, "a", offset);
7560             }
7561         }
7562     }
7563
7564 release:
7565   freeAsmop (result, NULL, ic, TRUE);
7566   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7567   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7568 }
7569
7570 /*-----------------------------------------------------------------*/
7571 /* genOr  - code for or                                            */
7572 /*-----------------------------------------------------------------*/
7573 static void
7574 genOr (iCode * ic, iCode * ifx)
7575 {
7576   operand *left, *right, *result;
7577   int size, offset = 0;
7578   unsigned long lit = 0L;
7579   int bytelit = 0;
7580   bool     pushResult;
7581
7582   D (emitcode (";", "genOr"));
7583
7584   AOP_OP_3_NOFATAL (ic, pushResult);
7585   AOP_SET_LOCALS (ic);
7586
7587   if (pushResult)
7588   {
7589       genFarFarLogicOp(ic, "orl");
7590       return;
7591   }
7592
7593
7594 #ifdef DEBUG_TYPE
7595   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7596             AOP_TYPE (result),
7597             AOP_TYPE (left), AOP_TYPE (right));
7598   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7599             AOP_SIZE (result),
7600             AOP_SIZE (left), AOP_SIZE (right));
7601 #endif
7602
7603   /* if left is a literal & right is not then exchange them */
7604   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7605 #ifdef LOGIC_OPS_BROKEN
7606    || AOP_NEEDSACC (left) // I think this is a net loss now.
7607 #endif
7608       )
7609     {
7610       operand *tmp = right;
7611       right = left;
7612       left = tmp;
7613     }
7614
7615   /* if result = right then exchange them */
7616   if (sameRegs (AOP (result), AOP (right)))
7617     {
7618       operand *tmp = right;
7619       right = left;
7620       left = tmp;
7621     }
7622
7623   /* if right is bit then exchange them */
7624   if (AOP_TYPE (right) == AOP_CRY &&
7625       AOP_TYPE (left) != AOP_CRY)
7626     {
7627       operand *tmp = right;
7628       right = left;
7629       left = tmp;
7630     }
7631   if (AOP_TYPE (right) == AOP_LIT)
7632     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7633
7634   size = AOP_SIZE (result);
7635
7636   // if(bit | yy)
7637   // xx = bit | yy;
7638   if (AOP_TYPE (left) == AOP_CRY)
7639     {
7640       if (AOP_TYPE (right) == AOP_LIT)
7641         {
7642           // c = bit | literal;
7643           if (lit)
7644             {
7645               // lit != 0 => result = 1
7646               if (AOP_TYPE (result) == AOP_CRY)
7647                 {
7648                   if (size)
7649                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7650                   else if (ifx)
7651                     continueIfTrue (ifx);
7652                   goto release;
7653                 }
7654               emitcode ("setb", "c");
7655             }
7656           else
7657             {
7658               // lit == 0 => result = left
7659               if (size && sameRegs (AOP (result), AOP (left)))
7660                 goto release;
7661               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7662             }
7663         }
7664       else
7665         {
7666           if (AOP_TYPE (right) == AOP_CRY)
7667             {
7668               // c = bit | bit;
7669               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7670               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7671             }
7672           else
7673             {
7674               // c = bit | val;
7675               symbol *tlbl = newiTempLabel (NULL);
7676               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7677                 emitcode ("setb", "c");
7678               emitcode ("jb", "%s,!tlabel",
7679                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7680               toBoolean (right);
7681               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7682               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7683                 {
7684                   jmpTrueOrFalse (ifx, tlbl);
7685                   goto release;
7686                 }
7687               else
7688                 {
7689                   CLRC;
7690                   emitLabel (tlbl);
7691                 }
7692             }
7693         }
7694       // bit = c
7695       // val = c
7696       if (size)
7697         outBitC (result);
7698       // if(bit | ...)
7699       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7700            genIfxJump (ifx, "c");
7701       goto release;
7702     }
7703
7704   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7705   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7706   if ((AOP_TYPE (right) == AOP_LIT) &&
7707       (AOP_TYPE (result) == AOP_CRY) &&
7708       (AOP_TYPE (left) != AOP_CRY))
7709     {
7710       if (lit)
7711         {
7712           // result = 1
7713           if (size)
7714             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7715           else
7716             continueIfTrue (ifx);
7717           goto release;
7718         }
7719       else
7720         {
7721           // lit = 0, result = boolean(left)
7722           if (size)
7723             emitcode ("setb", "c");
7724           toBoolean (right);
7725           if (size)
7726             {
7727               symbol *tlbl = newiTempLabel (NULL);
7728               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7729               CLRC;
7730               emitLabel (tlbl);
7731             }
7732           else
7733             {
7734               genIfxJump (ifx, "a");
7735               goto release;
7736             }
7737         }
7738       outBitC (result);
7739       goto release;
7740     }
7741
7742   /* if left is same as result */
7743   if (sameRegs (AOP (result), AOP (left)))
7744     {
7745       for (; size--; offset++)
7746         {
7747           if (AOP_TYPE (right) == AOP_LIT)
7748             {
7749               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7750               if (bytelit == 0)
7751                 {
7752                   /* dummy read of volatile operand */
7753                   if (isOperandVolatile (left, FALSE))
7754                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7755                   else
7756                     continue;
7757                 }
7758               else if (bytelit == 0x0FF)
7759                 {
7760                   aopPut (result, "#0xFF", offset);
7761                 }
7762               else if (IS_AOP_PREG (left))
7763                 {
7764                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7765                   emitcode ("orl", "a,%s",
7766                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7767                   aopPut (result, "a", offset);
7768                 }
7769               else
7770                 {
7771                   emitcode ("orl", "%s,%s",
7772                             aopGet (left, offset, FALSE, TRUE, NULL),
7773                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7774                 }
7775             }
7776           else
7777             {
7778               if (AOP_TYPE (left) == AOP_ACC)
7779                 {
7780                   if (offset)
7781                     emitcode("mov", "a,b");
7782                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7783                 }
7784               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7785                 {
7786                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7787                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7788                   emitcode ("orl", "a,b");
7789                   aopPut (result, "a", offset);
7790                 }
7791               else if (aopGetUsesAcc (left, offset))
7792                 {
7793                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7794                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7795                   aopPut (result, "a", offset);
7796                 }
7797               else
7798                 {
7799                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7800                   if (IS_AOP_PREG (left))
7801                     {
7802                       emitcode ("orl", "a,%s",
7803                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7804                       aopPut (result, "a", offset);
7805                     }
7806                   else
7807                     {
7808                       emitcode ("orl", "%s,a",
7809                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7810                     }
7811                 }
7812             }
7813         }
7814     }
7815   else
7816     {
7817       // left & result in different registers
7818       if (AOP_TYPE (result) == AOP_CRY)
7819         {
7820           // result = bit
7821           // if(size), result in bit
7822           // if(!size && ifx), conditional oper: if(left | right)
7823           symbol *tlbl = newiTempLabel (NULL);
7824           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7825           if (size)
7826             emitcode ("setb", "c");
7827           while (sizer--)
7828             {
7829               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7830                   && AOP_TYPE(left)==AOP_ACC)
7831                 {
7832                   if (offset)
7833                     emitcode("mov", "a,b");
7834                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7835                 }
7836               else if (AOP_TYPE(left)==AOP_ACC)
7837                 {
7838                   if (!offset)
7839                     {
7840                       bool pushedB = pushB ();
7841                       emitcode("mov", "b,a");
7842                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7843                       emitcode("orl", "a,b");
7844                       popB (pushedB);
7845                     }
7846                   else
7847                     {
7848                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7849                       emitcode("orl", "a,b");
7850                     }
7851                 }
7852               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7853                 {
7854                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7855                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7856                   emitcode ("orl", "a,b");
7857                 }
7858               else if (aopGetUsesAcc (left, offset))
7859                 {
7860                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7861                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7862                 }
7863               else
7864                 {
7865                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7866                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7867               }
7868
7869               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7870               offset++;
7871             }
7872           if (size)
7873             {
7874               CLRC;
7875               emitLabel (tlbl);
7876               outBitC (result);
7877             }
7878           else if (ifx)
7879             jmpTrueOrFalse (ifx, tlbl);
7880           else
7881             emitLabel (tlbl);
7882         }
7883       else
7884         {
7885             _startLazyDPSEvaluation();
7886           for (; (size--); offset++)
7887             {
7888               // normal case
7889               // result = left | right
7890               if (AOP_TYPE (right) == AOP_LIT)
7891                 {
7892                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7893                   if (bytelit == 0)
7894                     {
7895                       aopPut (result,
7896                               aopGet (left, offset, FALSE, FALSE, NULL),
7897                               offset);
7898                       continue;
7899                     }
7900                   else if (bytelit == 0x0FF)
7901                     {
7902                       /* dummy read of volatile operand */
7903                       if (isOperandVolatile (left, FALSE))
7904                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7905                       aopPut (result, "#0xFF", offset);
7906                       continue;
7907                     }
7908                 }
7909               // faster than result <- left, orl result,right
7910               // and better if result is SFR
7911               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7912                   && AOP_TYPE(left)==AOP_ACC)
7913                 {
7914                   if (offset)
7915                     emitcode("mov", "a,b");
7916                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7917                 }
7918               else if (AOP_TYPE(left)==AOP_ACC)
7919                 {
7920                   if (!offset)
7921                     {
7922                       bool pushedB = pushB ();
7923                       emitcode("mov", "b,a");
7924                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7925                       emitcode("orl", "a,b");
7926                       popB (pushedB);
7927                     }
7928                   else
7929                     {
7930                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7931                       emitcode("orl", "a,b");
7932                     }
7933                 }
7934               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7935                 {
7936                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7937                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7938                   emitcode ("orl", "a,b");
7939                 }
7940               else if (aopGetUsesAcc (left, offset))
7941                 {
7942                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7943                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7944                 }
7945               else
7946                 {
7947                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7948                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7949                 }
7950               aopPut (result, "a", offset);
7951             }
7952             _endLazyDPSEvaluation();
7953         }
7954     }
7955
7956 release:
7957   freeAsmop (result, NULL, ic, TRUE);
7958   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7959   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7960 }
7961
7962 /*-----------------------------------------------------------------*/
7963 /* genXor - code for xclusive or                                   */
7964 /*-----------------------------------------------------------------*/
7965 static void
7966 genXor (iCode * ic, iCode * ifx)
7967 {
7968   operand *left, *right, *result;
7969   int size, offset = 0;
7970   unsigned long lit = 0L;
7971   int bytelit = 0;
7972   bool pushResult;
7973
7974   D (emitcode (";", "genXor"));
7975
7976   AOP_OP_3_NOFATAL (ic, pushResult);
7977   AOP_SET_LOCALS (ic);
7978
7979   if (pushResult)
7980   {
7981       genFarFarLogicOp(ic, "xrl");
7982       return;
7983   }
7984
7985 #ifdef DEBUG_TYPE
7986   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7987             AOP_TYPE (result),
7988             AOP_TYPE (left), AOP_TYPE (right));
7989   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7990             AOP_SIZE (result),
7991             AOP_SIZE (left), AOP_SIZE (right));
7992 #endif
7993
7994   /* if left is a literal & right is not ||
7995      if left needs acc & right does not */
7996   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7997 #ifdef LOGIC_OPS_BROKEN
7998       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7999 #endif
8000      )
8001     {
8002       operand *tmp = right;
8003       right = left;
8004       left = tmp;
8005     }
8006
8007   /* if result = right then exchange them */
8008   if (sameRegs (AOP (result), AOP (right)))
8009     {
8010       operand *tmp = right;
8011       right = left;
8012       left = tmp;
8013     }
8014
8015   /* if right is bit then exchange them */
8016   if (AOP_TYPE (right) == AOP_CRY &&
8017       AOP_TYPE (left) != AOP_CRY)
8018     {
8019       operand *tmp = right;
8020       right = left;
8021       left = tmp;
8022     }
8023   if (AOP_TYPE (right) == AOP_LIT)
8024     lit = ulFromVal (AOP (right)->aopu.aop_lit);
8025
8026   size = AOP_SIZE (result);
8027
8028   // if(bit ^ yy)
8029   // xx = bit ^ yy;
8030   if (AOP_TYPE (left) == AOP_CRY)
8031     {
8032       if (AOP_TYPE (right) == AOP_LIT)
8033         {
8034           // c = bit & literal;
8035           if (lit >> 1)
8036             {
8037               // lit>>1  != 0 => result = 1
8038               if (AOP_TYPE (result) == AOP_CRY)
8039                 {
8040                   if (size)
8041                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8042                   else if (ifx)
8043                     continueIfTrue (ifx);
8044                   goto release;
8045                 }
8046               emitcode ("setb", "c");
8047             }
8048           else
8049             {
8050               // lit == (0 or 1)
8051               if (lit == 0)
8052                 {
8053                   // lit == 0, result = left
8054                   if (size && sameRegs (AOP (result), AOP (left)))
8055                     goto release;
8056                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8057                 }
8058               else
8059                 {
8060                   // lit == 1, result = not(left)
8061                   if (size && sameRegs (AOP (result), AOP (left)))
8062                     {
8063                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8064                       goto release;
8065                     }
8066                   else
8067                     {
8068                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8069                       emitcode ("cpl", "c");
8070                     }
8071                 }
8072             }
8073         }
8074       else
8075         {
8076           // right != literal
8077           symbol *tlbl = newiTempLabel (NULL);
8078           if (AOP_TYPE (right) == AOP_CRY)
8079             {
8080               // c = bit ^ bit;
8081               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8082             }
8083           else
8084             {
8085               int sizer = AOP_SIZE (right);
8086               // c = bit ^ val
8087               // if val>>1 != 0, result = 1
8088               emitcode ("setb", "c");
8089               while (sizer)
8090                 {
8091                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8092                   if (sizer == 1)
8093                     // test the msb of the lsb
8094                     emitcode ("anl", "a,#!constbyte",0xfe);
8095                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8096                   sizer--;
8097                 }
8098               // val = (0,1)
8099               emitcode ("rrc", "a");
8100             }
8101           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8102           emitcode ("cpl", "c");
8103           emitLabel (tlbl);
8104         }
8105       // bit = c
8106       // val = c
8107       if (size)
8108         outBitC (result);
8109       // if(bit | ...)
8110       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8111         genIfxJump (ifx, "c");
8112       goto release;
8113     }
8114
8115   /* if left is same as result */
8116   if (sameRegs (AOP (result), AOP (left)))
8117     {
8118       for (; size--; offset++)
8119         {
8120           if (AOP_TYPE (right) == AOP_LIT)
8121             {
8122               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8123               if (bytelit == 0)
8124                 {
8125                   /* dummy read of volatile operand */
8126                   if (isOperandVolatile (left, FALSE))
8127                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8128                   else
8129                     continue;
8130                 }
8131               else if (IS_AOP_PREG (left))
8132                 {
8133                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8134                   emitcode ("xrl", "a,%s",
8135                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8136                   aopPut (result, "a", offset);
8137                 }
8138               else
8139                 {
8140                   emitcode ("xrl", "%s,%s",
8141                             aopGet (left, offset, FALSE, TRUE, NULL),
8142                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8143                 }
8144             }
8145           else
8146             {
8147               if (AOP_TYPE (left) == AOP_ACC)
8148                 {
8149                   if (offset)
8150                     emitcode("mov", "a,b");
8151                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8152                 }
8153               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8154                 {
8155                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8156                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8157                   emitcode ("xrl", "a,b");
8158                   aopPut (result, "a", offset);
8159                 }
8160               else if (aopGetUsesAcc (left, offset))
8161                 {
8162                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8163                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8164                   aopPut (result, "a", offset);
8165                 }
8166               else
8167                 {
8168                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8169                   if (IS_AOP_PREG (left))
8170                     {
8171                       emitcode ("xrl", "a,%s",
8172                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8173                       aopPut (result, "a", offset);
8174                     }
8175                   else
8176                     emitcode ("xrl", "%s,a",
8177                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8178                 }
8179             }
8180         }
8181     }
8182   else
8183     {
8184       // left & result in different registers
8185       if (AOP_TYPE (result) == AOP_CRY)
8186         {
8187           // result = bit
8188           // if(size), result in bit
8189           // if(!size && ifx), conditional oper: if(left ^ right)
8190           symbol *tlbl = newiTempLabel (NULL);
8191           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8192
8193           if (size)
8194             emitcode ("setb", "c");
8195           while (sizer--)
8196             {
8197               if ((AOP_TYPE (right) == AOP_LIT) &&
8198                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8199                 {
8200                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8201                 }
8202               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8203                   && AOP_TYPE(left)==AOP_ACC)
8204                 {
8205                   if (offset)
8206                     emitcode("mov", "a,b");
8207                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8208                 }
8209               else if (AOP_TYPE(left)==AOP_ACC)
8210                 {
8211                   if (!offset)
8212                     {
8213                       bool pushedB = pushB ();
8214                       emitcode("mov", "b,a");
8215                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8216                       emitcode("xrl", "a,b");
8217                       popB (pushedB);
8218                     }
8219                   else
8220                     {
8221                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8222                       emitcode("xrl", "a,b");
8223                     }
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                 }
8231               else if (aopGetUsesAcc (left, offset))
8232                 {
8233                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8234                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8235                 }
8236               else
8237                 {
8238                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8239                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8240                 }
8241
8242               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8243               offset++;
8244             }
8245           if (size)
8246             {
8247               CLRC;
8248               emitLabel (tlbl);
8249               outBitC (result);
8250             }
8251           else if (ifx)
8252             jmpTrueOrFalse (ifx, tlbl);
8253         }
8254       else
8255         {
8256         for (; (size--); offset++)
8257           {
8258             // normal case
8259             // result = left ^ right
8260             if (AOP_TYPE (right) == AOP_LIT)
8261               {
8262                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8263                 if (bytelit == 0)
8264                   {
8265                     aopPut (result,
8266                             aopGet (left, offset, FALSE, FALSE, NULL),
8267                             offset);
8268                     continue;
8269                   }
8270                 D (emitcode (";", "better literal XOR."));
8271                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8272                 emitcode ("xrl", "a, %s",
8273                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8274               }
8275             else
8276               {
8277                 // faster than result <- left, anl result,right
8278                 // and better if result is SFR
8279                 if (AOP_TYPE (left) == AOP_ACC)
8280                   {
8281                     emitcode ("xrl", "a,%s",
8282                               aopGet (right, offset,
8283                                       FALSE, FALSE, DP2_RESULT_REG));
8284                   }
8285                 else
8286                   {
8287                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8288                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8289                       {
8290                           emitcode("mov", "b,a");
8291                           rOp = "b";
8292                       }
8293
8294                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8295                       emitcode ("xrl", "a,%s", rOp);
8296                   }
8297               }
8298             aopPut (result, "a", offset);
8299           }
8300         }
8301     }
8302
8303 release:
8304   freeAsmop (result, NULL, ic, TRUE);
8305   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8306   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8307 }
8308
8309 /*-----------------------------------------------------------------*/
8310 /* genInline - write the inline code out                           */
8311 /*-----------------------------------------------------------------*/
8312 static void
8313 genInline (iCode * ic)
8314 {
8315   char *buffer, *bp, *bp1;
8316   bool inComment = FALSE;
8317
8318   D (emitcode (";", "genInline"));
8319
8320   _G.inLine += (!options.asmpeep);
8321
8322   buffer = bp = bp1 = Safe_strdup (IC_INLINE(ic));
8323
8324   /* emit each line as a code */
8325   while (*bp)
8326     {
8327       switch (*bp)
8328         {
8329         case ';':
8330           inComment = TRUE;
8331           ++bp;
8332           break;
8333
8334         case '\n':
8335           inComment = FALSE;
8336           *bp++ = '\0';
8337           emitcode (bp1, "");
8338           bp1 = bp;
8339           break;
8340
8341         default:
8342           /* Add \n for labels, not dirs such as c:\mydir */
8343           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8344             {
8345               ++bp;
8346               *bp = '\0';
8347               ++bp;
8348               emitcode (bp1, "");
8349               bp1 = bp;
8350             }
8351           else
8352             ++bp;
8353           break;
8354         }
8355     }
8356   if (bp1 != bp)
8357     emitcode (bp1, "");
8358
8359   Safe_free (buffer);
8360
8361   _G.inLine -= (!options.asmpeep);
8362 }
8363
8364 /*-----------------------------------------------------------------*/
8365 /* genRRC - rotate right with carry                                */
8366 /*-----------------------------------------------------------------*/
8367 static void
8368 genRRC (iCode * ic)
8369 {
8370   operand *left, *result;
8371   int     size, offset;
8372   char *l;
8373
8374   D (emitcode (";", "genRRC"));
8375
8376   /* rotate right with carry */
8377   left = IC_LEFT (ic);
8378   result = IC_RESULT (ic);
8379   aopOp (left, ic, FALSE, FALSE);
8380   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8381
8382   /* move it to the result */
8383   size = AOP_SIZE (result);
8384   offset = size - 1;
8385   CLRC;
8386
8387   _startLazyDPSEvaluation ();
8388   while (size--)
8389     {
8390       l = aopGet (left, offset, FALSE, FALSE, NULL);
8391       MOVA (l);
8392       emitcode ("rrc", "a");
8393       if (AOP_SIZE (result) > 1)
8394         aopPut (result, "a", offset--);
8395     }
8396   _endLazyDPSEvaluation ();
8397
8398   /* now we need to put the carry into the
8399      highest order byte of the result */
8400   if (AOP_SIZE (result) > 1)
8401     {
8402       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8403       MOVA (l);
8404     }
8405   emitcode ("mov", "acc.7,c");
8406   aopPut (result, "a", AOP_SIZE (result) - 1);
8407   freeAsmop (result, NULL, ic, TRUE);
8408   freeAsmop (left, NULL, ic, TRUE);
8409 }
8410
8411 /*-----------------------------------------------------------------*/
8412 /* genRLC - generate code for rotate left with carry               */
8413 /*-----------------------------------------------------------------*/
8414 static void
8415 genRLC (iCode * ic)
8416 {
8417   operand *left, *result;
8418   int size, offset;
8419   char *l;
8420
8421   D (emitcode (";", "genRLC"));
8422
8423   /* rotate right with carry */
8424   left = IC_LEFT (ic);
8425   result = IC_RESULT (ic);
8426   aopOp (left, ic, FALSE, FALSE);
8427   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8428
8429   /* move it to the result */
8430   size = AOP_SIZE (result);
8431   offset = 0;
8432   if (size--)
8433     {
8434       l = aopGet (left, offset, FALSE, FALSE, NULL);
8435       MOVA (l);
8436       emitcode ("add", "a,acc");
8437       if (AOP_SIZE (result) > 1)
8438         {
8439           aopPut (result, "a", offset++);
8440         }
8441
8442       _startLazyDPSEvaluation ();
8443       while (size--)
8444         {
8445           l = aopGet (left, offset, FALSE, FALSE, NULL);
8446           MOVA (l);
8447           emitcode ("rlc", "a");
8448           if (AOP_SIZE (result) > 1)
8449             aopPut (result, "a", offset++);
8450         }
8451       _endLazyDPSEvaluation ();
8452     }
8453   /* now we need to put the carry into the
8454      highest order byte of the result */
8455   if (AOP_SIZE (result) > 1)
8456     {
8457       l = aopGet (result, 0, FALSE, FALSE, NULL);
8458       MOVA (l);
8459     }
8460   emitcode ("mov", "acc.0,c");
8461   aopPut (result, "a", 0);
8462   freeAsmop (result, NULL, ic, TRUE);
8463   freeAsmop (left, NULL, ic, TRUE);
8464 }
8465
8466 /*-----------------------------------------------------------------*/
8467 /* genGetHbit - generates code get highest order bit               */
8468 /*-----------------------------------------------------------------*/
8469 static void
8470 genGetHbit (iCode * ic)
8471 {
8472   operand *left, *result;
8473
8474   D (emitcode (";", "genGetHbit"));
8475
8476   left = IC_LEFT (ic);
8477   result = IC_RESULT (ic);
8478   aopOp (left, ic, FALSE, FALSE);
8479   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8480
8481   /* get the highest order byte into a */
8482   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8483   if (AOP_TYPE (result) == AOP_CRY)
8484     {
8485       emitcode ("rlc", "a");
8486       outBitC (result);
8487     }
8488   else
8489     {
8490       emitcode ("rl", "a");
8491       emitcode ("anl", "a,#1");
8492       outAcc (result);
8493     }
8494
8495
8496   freeAsmop (result, NULL, ic, TRUE);
8497   freeAsmop (left, NULL, ic, TRUE);
8498 }
8499
8500 /*-----------------------------------------------------------------*/
8501 /* genSwap - generates code to swap nibbles or bytes               */
8502 /*-----------------------------------------------------------------*/
8503 static void
8504 genSwap (iCode * ic)
8505 {
8506   operand *left, *result;
8507
8508   D(emitcode (";", "genSwap"));
8509
8510   left = IC_LEFT (ic);
8511   result = IC_RESULT (ic);
8512   aopOp (left, ic, FALSE, FALSE);
8513   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8514
8515   _startLazyDPSEvaluation ();
8516   switch (AOP_SIZE (left))
8517     {
8518     case 1: /* swap nibbles in byte */
8519       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8520       emitcode ("swap", "a");
8521       aopPut (result, "a", 0);
8522       break;
8523     case 2: /* swap bytes in word */
8524       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8525         {
8526           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8527           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8528           aopPut (result, "a", 1);
8529         }
8530       else if (operandsEqu (left, result))
8531         {
8532           char * reg = "a";
8533           bool pushedB = FALSE, leftInB = FALSE;
8534
8535           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8536           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8537             {
8538               pushedB = pushB ();
8539               emitcode ("mov", "b,a");
8540               reg = "b";
8541               leftInB = TRUE;
8542             }
8543           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8544           aopPut (result, reg, 1);
8545
8546           if (leftInB)
8547             popB (pushedB);
8548         }
8549       else
8550         {
8551           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8552           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8553         }
8554       break;
8555     default:
8556       wassertl(FALSE, "unsupported SWAP operand size");
8557     }
8558   _endLazyDPSEvaluation ();
8559
8560   freeAsmop (result, NULL, ic, TRUE);
8561   freeAsmop (left, NULL, ic, TRUE);
8562 }
8563
8564 /*-----------------------------------------------------------------*/
8565 /* AccRol - rotate left accumulator by known count                 */
8566 /*-----------------------------------------------------------------*/
8567 static void
8568 AccRol (int shCount)
8569 {
8570   shCount &= 0x0007;            // shCount : 0..7
8571
8572   switch (shCount)
8573     {
8574     case 0:
8575       break;
8576     case 1:
8577       emitcode ("rl", "a");
8578       break;
8579     case 2:
8580       emitcode ("rl", "a");
8581       emitcode ("rl", "a");
8582       break;
8583     case 3:
8584       emitcode ("swap", "a");
8585       emitcode ("rr", "a");
8586       break;
8587     case 4:
8588       emitcode ("swap", "a");
8589       break;
8590     case 5:
8591       emitcode ("swap", "a");
8592       emitcode ("rl", "a");
8593       break;
8594     case 6:
8595       emitcode ("rr", "a");
8596       emitcode ("rr", "a");
8597       break;
8598     case 7:
8599       emitcode ("rr", "a");
8600       break;
8601     }
8602 }
8603
8604 /*-----------------------------------------------------------------*/
8605 /* AccLsh - left shift accumulator by known count                  */
8606 /*-----------------------------------------------------------------*/
8607 static void
8608 AccLsh (int shCount)
8609 {
8610   if (shCount != 0)
8611     {
8612       if (shCount == 1)
8613         emitcode ("add", "a,acc");
8614       else if (shCount == 2)
8615         {
8616           emitcode ("add", "a,acc");
8617           emitcode ("add", "a,acc");
8618         }
8619       else
8620         {
8621           /* rotate left accumulator */
8622           AccRol (shCount);
8623           /* and kill the lower order bits */
8624           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8625         }
8626     }
8627 }
8628
8629 /*-----------------------------------------------------------------*/
8630 /* AccRsh - right shift accumulator by known count                 */
8631 /*-----------------------------------------------------------------*/
8632 static void
8633 AccRsh (int shCount)
8634 {
8635   if (shCount != 0)
8636     {
8637       if (shCount == 1)
8638         {
8639           CLRC;
8640           emitcode ("rrc", "a");
8641         }
8642       else
8643         {
8644           /* rotate right accumulator */
8645           AccRol (8 - shCount);
8646           /* and kill the higher order bits */
8647           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8648         }
8649     }
8650 }
8651
8652 #ifdef BETTER_LITERAL_SHIFT
8653 /*-----------------------------------------------------------------*/
8654 /* AccSRsh - signed right shift accumulator by known count                 */
8655 /*-----------------------------------------------------------------*/
8656 static void
8657 AccSRsh (int shCount)
8658 {
8659   symbol *tlbl;
8660   if (shCount != 0)
8661     {
8662       if (shCount == 1)
8663         {
8664           emitcode ("mov", "c,acc.7");
8665           emitcode ("rrc", "a");
8666         }
8667       else if (shCount == 2)
8668         {
8669           emitcode ("mov", "c,acc.7");
8670           emitcode ("rrc", "a");
8671           emitcode ("mov", "c,acc.7");
8672           emitcode ("rrc", "a");
8673         }
8674       else
8675         {
8676           tlbl = newiTempLabel (NULL);
8677           /* rotate right accumulator */
8678           AccRol (8 - shCount);
8679           /* and kill the higher order bits */
8680           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8681           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8682           emitcode ("orl", "a,#!constbyte",
8683                     (unsigned char) ~SRMask[shCount]);
8684           emitLabel (tlbl);
8685         }
8686     }
8687 }
8688 #endif
8689
8690 #ifdef BETTER_LITERAL_SHIFT
8691 /*-----------------------------------------------------------------*/
8692 /* shiftR1Left2Result - shift right one byte from left to result   */
8693 /*-----------------------------------------------------------------*/
8694 static void
8695 shiftR1Left2Result (operand * left, int offl,
8696                     operand * result, int offr,
8697                     int shCount, int sign)
8698 {
8699   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8700   /* shift right accumulator */
8701   if (sign)
8702     AccSRsh (shCount);
8703   else
8704     AccRsh (shCount);
8705   aopPut (result, "a", offr);
8706 }
8707 #endif
8708
8709 #ifdef BETTER_LITERAL_SHIFT
8710 /*-----------------------------------------------------------------*/
8711 /* shiftL1Left2Result - shift left one byte from left to result    */
8712 /*-----------------------------------------------------------------*/
8713 static void
8714 shiftL1Left2Result (operand * left, int offl,
8715                     operand * result, int offr, int shCount)
8716 {
8717   char *l;
8718   l = aopGet (left, offl, FALSE, FALSE, NULL);
8719   MOVA (l);
8720   /* shift left accumulator */
8721   AccLsh (shCount);
8722   aopPut (result, "a", offr);
8723 }
8724 #endif
8725
8726 #ifdef BETTER_LITERAL_SHIFT
8727 /*-----------------------------------------------------------------*/
8728 /* movLeft2Result - move byte from left to result                  */
8729 /*-----------------------------------------------------------------*/
8730 static void
8731 movLeft2Result (operand * left, int offl,
8732                 operand * result, int offr, int sign)
8733 {
8734   char *l;
8735   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8736   {
8737       l = aopGet (left, offl, FALSE, FALSE, NULL);
8738
8739       if (*l == '@' && (IS_AOP_PREG (result)))
8740       {
8741           emitcode ("mov", "a,%s", l);
8742           aopPut (result, "a", offr);
8743       }
8744       else
8745       {
8746           if (!sign)
8747             {
8748               aopPut (result, l, offr);
8749             }
8750           else
8751             {
8752               /* MSB sign in acc.7 ! */
8753               if (getDataSize (left) == offl + 1)
8754                 {
8755                   MOVA (l);
8756                   aopPut (result, "a", offr);
8757                 }
8758             }
8759       }
8760   }
8761 }
8762 #endif
8763
8764 #ifdef BETTER_LITERAL_SHIFT
8765 /*-----------------------------------------------------------------*/
8766 /* AccAXRrl1 - right rotate a:x by 1                               */
8767 /*-----------------------------------------------------------------*/
8768 static void
8769 AccAXRrl1 (char *x)
8770 {
8771   emitcode ("mov", "c,acc.0");
8772   emitcode ("xch", "a,%s", x);
8773   emitcode ("rrc", "a");
8774   emitcode ("xch", "a,%s", x);
8775   emitcode ("rrc", "a");
8776 }
8777 #endif
8778
8779 #ifdef BETTER_LITERAL_SHIFT
8780 //REMOVE ME!!!
8781 /*-----------------------------------------------------------------*/
8782 /* AccAXLrl1 - left rotate a:x by 1                                */
8783 /*-----------------------------------------------------------------*/
8784 static void
8785 AccAXLrl1 (char *x)
8786 {
8787   emitcode ("mov", "c,acc.7");
8788   emitcode ("xch", "a,%s", x);
8789   emitcode ("rlc", "a");
8790   emitcode ("xch", "a,%s", x);
8791   emitcode ("rlc", "a");
8792 }
8793 #endif
8794
8795 #ifdef BETTER_LITERAL_SHIFT
8796 /*-----------------------------------------------------------------*/
8797 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8798 /*-----------------------------------------------------------------*/
8799 static void
8800 AccAXRsh1 (char *x)
8801 {
8802   emitcode ("rrc", "a");
8803   emitcode ("xch", "a,%s", x);
8804   emitcode ("rrc", "a");
8805   emitcode ("xch", "a,%s", x);
8806 }
8807 #endif
8808
8809 #ifdef BETTER_LITERAL_SHIFT
8810 /*-----------------------------------------------------------------*/
8811 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8812 /*-----------------------------------------------------------------*/
8813 static void
8814 AccAXLsh1 (char *x)
8815 {
8816   emitcode ("xch", "a,%s", x);
8817   emitcode ("add", "a,acc");
8818   emitcode ("xch", "a,%s", x);
8819   emitcode ("rlc", "a");
8820 }
8821 #endif
8822
8823 #ifdef BETTER_LITERAL_SHIFT
8824 /*-----------------------------------------------------------------*/
8825 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8826 /*-----------------------------------------------------------------*/
8827 static void
8828 AccAXLsh (char *x, int shCount)
8829 {
8830   switch (shCount)
8831     {
8832     case 0:
8833       break;
8834     case 1:
8835       AccAXLsh1 (x);
8836       break;
8837     case 2:
8838       AccAXLsh1 (x);
8839       AccAXLsh1 (x);
8840       break;
8841     case 3:
8842     case 4:
8843     case 5:                             // AAAAABBB:CCCCCDDD
8844
8845       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8846
8847       emitcode ("anl", "a,#!constbyte",
8848                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8849
8850       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8851
8852       AccRol (shCount);                 // DDDCCCCC:BBB00000
8853
8854       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8855
8856       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8857
8858       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8859
8860       emitcode ("anl", "a,#!constbyte",
8861                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8862
8863       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8864
8865       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8866
8867       break;
8868     case 6:                             // AAAAAABB:CCCCCCDD
8869       emitcode ("anl", "a,#!constbyte",
8870                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8871 #if 1
8872       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8873       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8874       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8875 #else
8876       emitcode ("mov", "c,acc.0");      // c = B
8877       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8878       emitcode("rrc","a");
8879       emitcode("xch","a,%s", x);
8880       emitcode("rrc","a");
8881       emitcode("mov","c,acc.0"); //<< get correct bit
8882       emitcode("xch","a,%s", x);
8883
8884       emitcode("rrc","a");
8885       emitcode("xch","a,%s", x);
8886       emitcode("rrc","a");
8887       emitcode("xch","a,%s", x);
8888 #endif
8889       break;
8890     case 7:                             // a:x <<= 7
8891
8892       emitcode ("anl", "a,#!constbyte",
8893                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8894
8895       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8896
8897       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8898
8899       break;
8900     default:
8901       break;
8902     }
8903 }
8904 #endif
8905
8906 #ifdef BETTER_LITERAL_SHIFT
8907 //REMOVE ME!!!
8908 /*-----------------------------------------------------------------*/
8909 /* AccAXRsh - right shift a:x known count (0..7)                   */
8910 /*-----------------------------------------------------------------*/
8911 static void
8912 AccAXRsh (char *x, int shCount)
8913 {
8914   switch (shCount)
8915     {
8916     case 0:
8917       break;
8918     case 1:
8919       CLRC;
8920       AccAXRsh1 (x);                    // 0->a:x
8921
8922       break;
8923     case 2:
8924       CLRC;
8925       AccAXRsh1 (x);                    // 0->a:x
8926
8927       CLRC;
8928       AccAXRsh1 (x);                    // 0->a:x
8929
8930       break;
8931     case 3:
8932     case 4:
8933     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8934
8935       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8936
8937       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8938
8939       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8940
8941       emitcode ("anl", "a,#!constbyte",
8942                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8943
8944       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8945
8946       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8947
8948       emitcode ("anl", "a,#!constbyte",
8949                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8950
8951       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8952
8953       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8954
8955       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8956
8957       break;
8958     case 6:                             // AABBBBBB:CCDDDDDD
8959
8960       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8961       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8962
8963       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8964
8965       emitcode ("anl", "a,#!constbyte",
8966                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8967
8968       break;
8969     case 7:                             // ABBBBBBB:CDDDDDDD
8970
8971       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8972
8973       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8974
8975       emitcode ("anl", "a,#!constbyte",
8976                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8977
8978       break;
8979     default:
8980       break;
8981     }
8982 }
8983 #endif
8984
8985 #ifdef BETTER_LITERAL_SHIFT
8986 /*-----------------------------------------------------------------*/
8987 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8988 /*-----------------------------------------------------------------*/
8989 static void
8990 AccAXRshS (char *x, int shCount)
8991 {
8992   symbol *tlbl;
8993   switch (shCount)
8994     {
8995     case 0:
8996       break;
8997     case 1:
8998       emitcode ("mov", "c,acc.7");
8999       AccAXRsh1 (x);                    // s->a:x
9000
9001       break;
9002     case 2:
9003       emitcode ("mov", "c,acc.7");
9004       AccAXRsh1 (x);                    // s->a:x
9005
9006       emitcode ("mov", "c,acc.7");
9007       AccAXRsh1 (x);                    // s->a:x
9008
9009       break;
9010     case 3:
9011     case 4:
9012     case 5:                             // AAAAABBB:CCCCCDDD = a:x
9013
9014       tlbl = newiTempLabel (NULL);
9015       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9016
9017       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9018
9019       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9020
9021       emitcode ("anl", "a,#!constbyte",
9022                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9023
9024       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9025
9026       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9027
9028       emitcode ("anl", "a,#!constbyte",
9029                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9030
9031       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9032
9033       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9034
9035       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9036
9037       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9038       emitcode ("orl", "a,#!constbyte",
9039                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9040
9041       emitLabel (tlbl);
9042       break;                            // SSSSAAAA:BBBCCCCC
9043
9044     case 6:                             // AABBBBBB:CCDDDDDD
9045
9046       tlbl = newiTempLabel (NULL);
9047
9048       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9049       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9050
9051       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9052
9053       emitcode ("anl", "a,#!constbyte",
9054                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9055
9056       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9057       emitcode ("orl", "a,#!constbyte",
9058                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9059
9060       emitLabel (tlbl);
9061       break;
9062     case 7:                             // ABBBBBBB:CDDDDDDD
9063
9064       tlbl = newiTempLabel (NULL);
9065
9066       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9067
9068       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9069
9070       emitcode ("anl", "a,#!constbyte",
9071                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9072
9073       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9074       emitcode ("orl", "a,#!constbyte",
9075                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9076
9077       emitLabel (tlbl);
9078       break;
9079     default:
9080       break;
9081     }
9082 }
9083 #endif
9084
9085 #ifdef BETTER_LITERAL_SHIFT
9086 static void
9087 _loadLeftIntoAx(char    **lsb,
9088                 operand *left,
9089                 operand *result,
9090                 int     offl,
9091                 int     offr)
9092 {
9093   // Get the initial value from left into a pair of registers.
9094   // MSB must be in A, LSB can be any register.
9095   //
9096   // If the result is held in registers, it is an optimization
9097   // if the LSB can be held in the register which will hold the,
9098   // result LSB since this saves us from having to copy it into
9099   // the result following AccAXLsh.
9100   //
9101   // If the result is addressed indirectly, this is not a gain.
9102   if (AOP_NEEDSACC(result))
9103   {
9104        char *leftByte;
9105
9106        _startLazyDPSEvaluation();
9107       if (AOP_TYPE(left) == AOP_DPTR2)
9108        {
9109            // Get MSB in A.
9110            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9111            // get LSB in DP2_RESULT_REG.
9112            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9113            assert(!strcmp(leftByte, DP2_RESULT_REG));
9114        }
9115        else
9116        {
9117            // get LSB into DP2_RESULT_REG
9118            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9119            if (strcmp(leftByte, DP2_RESULT_REG))
9120            {
9121                TR_AP("#7");
9122                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9123            }
9124            // And MSB in A.
9125            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9126            assert(strcmp(leftByte, DP2_RESULT_REG));
9127            MOVA (leftByte);
9128        }
9129        _endLazyDPSEvaluation();
9130        *lsb = DP2_RESULT_REG;
9131   }
9132   else
9133   {
9134       if (sameRegs (AOP (result), AOP (left)) &&
9135         ((offl + MSB16) == offr))
9136       {
9137           /* don't crash result[offr] */
9138           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9139           emitcode ("xch", "a,%s",
9140                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9141       }
9142       else
9143       {
9144           movLeft2Result (left, offl, result, offr, 0);
9145           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9146       }
9147       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9148       assert(strcmp(*lsb,"a"));
9149   }
9150 }
9151
9152 static void
9153 _storeAxResults(char    *lsb,
9154                 operand *result,
9155                 int     offr)
9156 {
9157   _startLazyDPSEvaluation();
9158   if (AOP_NEEDSACC(result))
9159   {
9160       /* We have to explicitly update the result LSB.
9161        */
9162       emitcode ("xch","a,%s", lsb);
9163       aopPut (result, "a", offr);
9164       emitcode ("mov","a,%s", lsb);
9165   }
9166   if (getDataSize (result) > 1)
9167   {
9168       aopPut (result, "a", offr + MSB16);
9169   }
9170   _endLazyDPSEvaluation();
9171 }
9172
9173 /*-----------------------------------------------------------------*/
9174 /* shiftL2Left2Result - shift left two bytes from left to result   */
9175 /*-----------------------------------------------------------------*/
9176 static void
9177 shiftL2Left2Result (operand * left, int offl,
9178                     operand * result, int offr, int shCount)
9179 {
9180   char *lsb;
9181
9182   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9183
9184   AccAXLsh (lsb, shCount);
9185
9186   _storeAxResults(lsb, result, offr);
9187 }
9188 #endif
9189
9190 #ifdef BETTER_LITERAL_SHIFT
9191 /*-----------------------------------------------------------------*/
9192 /* shiftR2Left2Result - shift right two bytes from left to result  */
9193 /*-----------------------------------------------------------------*/
9194 static void
9195 shiftR2Left2Result (operand * left, int offl,
9196                     operand * result, int offr,
9197                     int shCount, int sign)
9198 {
9199   char *lsb;
9200
9201   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9202
9203   /* a:x >> shCount (x = lsb(result)) */
9204   if (sign)
9205   {
9206      AccAXRshS(lsb, shCount);
9207   }
9208   else
9209   {
9210     AccAXRsh(lsb, shCount);
9211   }
9212
9213   _storeAxResults(lsb, result, offr);
9214 }
9215 #endif
9216
9217 /*-----------------------------------------------------------------*/
9218 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9219 /*-----------------------------------------------------------------*/
9220 static void
9221 shiftLLeftOrResult (operand * left, int offl,
9222                     operand * result, int offr, int shCount)
9223 {
9224   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9225   /* shift left accumulator */
9226   AccLsh (shCount);
9227   /* or with result */
9228   emitcode ("orl", "a,%s",
9229             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9230   /* back to result */
9231   aopPut (result, "a", offr);
9232 }
9233
9234 #if 0
9235 //REMOVE ME!!!
9236 /*-----------------------------------------------------------------*/
9237 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9238 /*-----------------------------------------------------------------*/
9239 static void
9240 shiftRLeftOrResult (operand * left, int offl,
9241                     operand * result, int offr, int shCount)
9242 {
9243   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9244   /* shift right accumulator */
9245   AccRsh (shCount);
9246   /* or with result */
9247   emitcode ("orl", "a,%s",
9248             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9249   /* back to result */
9250   aopPut (result, "a", offr);
9251 }
9252 #endif
9253
9254 #ifdef BETTER_LITERAL_SHIFT
9255 /*-----------------------------------------------------------------*/
9256 /* genlshOne - left shift a one byte quantity by known count       */
9257 /*-----------------------------------------------------------------*/
9258 static void
9259 genlshOne (operand * result, operand * left, int shCount)
9260 {
9261   D (emitcode (";", "genlshOne"));
9262
9263   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9264 }
9265 #endif
9266
9267 #ifdef BETTER_LITERAL_SHIFT
9268 /*-----------------------------------------------------------------*/
9269 /* genlshTwo - left shift two bytes by known amount != 0           */
9270 /*-----------------------------------------------------------------*/
9271 static void
9272 genlshTwo (operand * result, operand * left, int shCount)
9273 {
9274   int size;
9275
9276   D (emitcode (";", "genlshTwo"));
9277
9278   size = getDataSize (result);
9279
9280   /* if shCount >= 8 */
9281   if (shCount >= 8)
9282   {
9283       shCount -= 8;
9284
9285       _startLazyDPSEvaluation();
9286
9287       if (size > 1)
9288         {
9289           if (shCount)
9290           {
9291             _endLazyDPSEvaluation();
9292             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9293             aopPut (result, zero, LSB);
9294           }
9295           else
9296           {
9297             movLeft2Result (left, LSB, result, MSB16, 0);
9298             aopPut (result, zero, LSB);
9299             _endLazyDPSEvaluation();
9300           }
9301         }
9302         else
9303         {
9304           aopPut (result, zero, LSB);
9305           _endLazyDPSEvaluation();
9306         }
9307   }
9308
9309   /*  1 <= shCount <= 7 */
9310   else
9311     {
9312       if (size == 1)
9313         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9314       else
9315         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9316     }
9317 }
9318 #endif
9319
9320 #if 0
9321 //REMOVE ME!!!
9322 /*-----------------------------------------------------------------*/
9323 /* shiftLLong - shift left one long from left to result            */
9324 /* offl = LSB or MSB16                                             */
9325 /*-----------------------------------------------------------------*/
9326 static void
9327 shiftLLong (operand * left, operand * result, int offr)
9328 {
9329   char *l;
9330   int size = AOP_SIZE (result);
9331
9332   if (size >= LSB + offr)
9333     {
9334       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9335       MOVA (l);
9336       emitcode ("add", "a,acc");
9337       if (sameRegs (AOP (left), AOP (result)) &&
9338           size >= MSB16 + offr && offr != LSB)
9339         emitcode ("xch", "a,%s",
9340                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9341       else
9342         aopPut (result, "a", LSB + offr);
9343     }
9344
9345   if (size >= MSB16 + offr)
9346     {
9347       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9348         {
9349           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9350           MOVA (l);
9351         }
9352       emitcode ("rlc", "a");
9353       if (sameRegs (AOP (left), AOP (result)) &&
9354           size >= MSB24 + offr && offr != LSB)
9355         emitcode ("xch", "a,%s",
9356                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9357       else
9358         aopPut (result, "a", MSB16 + offr);
9359     }
9360
9361   if (size >= MSB24 + offr)
9362     {
9363       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9364         {
9365           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9366           MOVA (l);
9367         }
9368       emitcode ("rlc", "a");
9369       if (sameRegs (AOP (left), AOP (result)) &&
9370           size >= MSB32 + offr && offr != LSB)
9371         emitcode ("xch", "a,%s",
9372                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9373       else
9374         aopPut (result, "a", MSB24 + offr);
9375     }
9376
9377   if (size > MSB32 + offr)
9378     {
9379       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9380         {
9381           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9382           MOVA (l);
9383         }
9384       emitcode ("rlc", "a");
9385       aopPut (result, "a", MSB32 + offr);
9386     }
9387   if (offr != LSB)
9388     aopPut (result, zero, LSB);
9389 }
9390 #endif
9391
9392 #if 0
9393 //REMOVE ME!!!
9394 /*-----------------------------------------------------------------*/
9395 /* genlshFour - shift four byte by a known amount != 0             */
9396 /*-----------------------------------------------------------------*/
9397 static void
9398 genlshFour (operand * result, operand * left, int shCount)
9399 {
9400   int size;
9401
9402   D (emitcode (";", "genlshFour"));
9403
9404   size = AOP_SIZE (result);
9405
9406   /* if shifting more that 3 bytes */
9407   if (shCount >= 24)
9408     {
9409       shCount -= 24;
9410       if (shCount)
9411         /* lowest order of left goes to the highest
9412            order of the destination */
9413         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9414       else
9415         movLeft2Result (left, LSB, result, MSB32, 0);
9416       aopPut (result, zero, LSB);
9417       aopPut (result, zero, MSB16);
9418       aopPut (result, zero, MSB24);
9419       return;
9420     }
9421
9422   /* more than two bytes */
9423   else if (shCount >= 16)
9424     {
9425       /* lower order two bytes goes to higher order two bytes */
9426       shCount -= 16;
9427       /* if some more remaining */
9428       if (shCount)
9429         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9430       else
9431         {
9432           movLeft2Result (left, MSB16, result, MSB32, 0);
9433           movLeft2Result (left, LSB, result, MSB24, 0);
9434         }
9435       aopPut (result, zero, MSB16);
9436       aopPut (result, zero, LSB);
9437       return;
9438     }
9439
9440   /* if more than 1 byte */
9441   else if (shCount >= 8)
9442     {
9443       /* lower order three bytes goes to higher order  three bytes */
9444       shCount -= 8;
9445       if (size == 2)
9446         {
9447           if (shCount)
9448             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9449           else
9450             movLeft2Result (left, LSB, result, MSB16, 0);
9451         }
9452       else
9453         {                       /* size = 4 */
9454           if (shCount == 0)
9455             {
9456               movLeft2Result (left, MSB24, result, MSB32, 0);
9457               movLeft2Result (left, MSB16, result, MSB24, 0);
9458               movLeft2Result (left, LSB, result, MSB16, 0);
9459               aopPut (result, zero, LSB);
9460             }
9461           else if (shCount == 1)
9462             shiftLLong (left, result, MSB16);
9463           else
9464             {
9465               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9466               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9467               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9468               aopPut (result, zero, LSB);
9469             }
9470         }
9471     }
9472
9473   /* 1 <= shCount <= 7 */
9474   else if (shCount <= 2)
9475     {
9476       shiftLLong (left, result, LSB);
9477       if (shCount == 2)
9478         shiftLLong (result, result, LSB);
9479     }
9480   /* 3 <= shCount <= 7, optimize */
9481   else
9482     {
9483       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9484       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9485       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9486     }
9487 }
9488 #endif
9489
9490 #ifdef BETTER_LITERAL_SHIFT
9491 /*-----------------------------------------------------------------*/
9492 /* genLeftShiftLiteral - left shifting by known count              */
9493 /*-----------------------------------------------------------------*/
9494 static bool
9495 genLeftShiftLiteral (operand * left,
9496                      operand * right,
9497                      operand * result,
9498                      iCode * ic)
9499 {
9500   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9501   int size;
9502
9503   size = getSize (operandType (result));
9504
9505   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9506
9507   /* We only handle certain easy cases so far. */
9508   if ((shCount != 0)
9509    && (shCount < (size * 8))
9510    && (size != 1)
9511    && (size != 2))
9512   {
9513       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9514       return FALSE;
9515   }
9516
9517   freeAsmop (right, NULL, ic, TRUE);
9518
9519   aopOp(left, ic, FALSE, FALSE);
9520   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9521
9522 #if 0 // debug spew
9523   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9524   {
9525         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9526         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9527         {
9528            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9529         }
9530   }
9531   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9532   {
9533         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9534         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9535         {
9536            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9537         }
9538   }
9539 #endif
9540
9541 #if VIEW_SIZE
9542   emitcode ("; shift left ", "result %d, left %d", size,
9543             AOP_SIZE (left));
9544 #endif
9545
9546   /* I suppose that the left size >= result size */
9547   if (shCount == 0)
9548   {
9549         _startLazyDPSEvaluation();
9550         while (size--)
9551         {
9552           movLeft2Result (left, size, result, size, 0);
9553         }
9554         _endLazyDPSEvaluation();
9555   }
9556   else if (shCount >= (size * 8))
9557   {
9558     _startLazyDPSEvaluation();
9559     while (size--)
9560     {
9561       aopPut (result, zero, size);
9562     }
9563     _endLazyDPSEvaluation();
9564   }
9565   else
9566   {
9567       switch (size)
9568         {
9569         case 1:
9570           genlshOne (result, left, shCount);
9571           break;
9572
9573         case 2:
9574           genlshTwo (result, left, shCount);
9575           break;
9576 #if 0
9577         case 4:
9578           genlshFour (result, left, shCount);
9579           break;
9580 #endif
9581         default:
9582           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9583                   "*** ack! mystery literal shift!\n");
9584           break;
9585         }
9586     }
9587   freeAsmop (result, NULL, ic, TRUE);
9588   freeAsmop (left, NULL, ic, TRUE);
9589   return TRUE;
9590 }
9591 #endif
9592
9593 /*-----------------------------------------------------------------*/
9594 /* genLeftShift - generates code for left shifting                 */
9595 /*-----------------------------------------------------------------*/
9596 static void
9597 genLeftShift (iCode * ic)
9598 {
9599   operand *left, *right, *result;
9600   int size, offset;
9601   char *l;
9602   symbol *tlbl, *tlbl1;
9603   bool pushedB;
9604
9605   D (emitcode (";", "genLeftShift"));
9606
9607   right = IC_RIGHT (ic);
9608   left = IC_LEFT (ic);
9609   result = IC_RESULT (ic);
9610
9611   aopOp (right, ic, FALSE, FALSE);
9612
9613
9614 #ifdef BETTER_LITERAL_SHIFT
9615   /* if the shift count is known then do it
9616      as efficiently as possible */
9617   if (AOP_TYPE (right) == AOP_LIT)
9618     {
9619       if (genLeftShiftLiteral (left, right, result, ic))
9620       {
9621         return;
9622       }
9623     }
9624 #endif
9625
9626   /* shift count is unknown then we have to form
9627      a loop get the loop count in B : Note: we take
9628      only the lower order byte since shifting
9629      more that 32 bits make no sense anyway, ( the
9630      largest size of an object can be only 32 bits ) */
9631
9632   pushedB = pushB ();
9633   if (AOP_TYPE (right) == AOP_LIT)
9634   {
9635       /* Really should be handled by genLeftShiftLiteral,
9636        * but since I'm too lazy to fix that today, at least we can make
9637        * some small improvement.
9638        */
9639        emitcode("mov", "b,#!constbyte",
9640                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
9641   }
9642   else
9643   {
9644       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9645       emitcode ("inc", "b");
9646   }
9647   freeAsmop (right, NULL, ic, TRUE);
9648   aopOp (left, ic, FALSE, FALSE);
9649   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9650
9651   /* now move the left to the result if they are not the same */
9652   if (!sameRegs (AOP (left), AOP (result)) &&
9653       AOP_SIZE (result) > 1)
9654     {
9655
9656       size = AOP_SIZE (result);
9657       offset = 0;
9658       _startLazyDPSEvaluation ();
9659       while (size--)
9660         {
9661           l = aopGet (left, offset, FALSE, TRUE, NULL);
9662           if (*l == '@' && (IS_AOP_PREG (result)))
9663             {
9664
9665               emitcode ("mov", "a,%s", l);
9666               aopPut (result, "a", offset);
9667             }
9668           else
9669             aopPut (result, l, offset);
9670           offset++;
9671         }
9672       _endLazyDPSEvaluation ();
9673     }
9674
9675   tlbl = newiTempLabel (NULL);
9676   size = AOP_SIZE (result);
9677   offset = 0;
9678   tlbl1 = newiTempLabel (NULL);
9679
9680   /* if it is only one byte then */
9681   if (size == 1)
9682     {
9683       symbol *tlbl1 = newiTempLabel (NULL);
9684
9685       l = aopGet (left, 0, FALSE, FALSE, NULL);
9686       MOVA (l);
9687       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9688       emitLabel (tlbl);
9689       emitcode ("add", "a,acc");
9690       emitLabel (tlbl1);
9691       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9692       popB (pushedB);
9693       aopPut (result, "a", 0);
9694       goto release;
9695     }
9696
9697   reAdjustPreg (AOP (result));
9698
9699   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9700   emitLabel (tlbl);
9701   l = aopGet (result, offset, FALSE, FALSE, NULL);
9702   MOVA (l);
9703   emitcode ("add", "a,acc");
9704   aopPut (result, "a", offset++);
9705   _startLazyDPSEvaluation ();
9706   while (--size)
9707     {
9708       l = aopGet (result, offset, FALSE, FALSE, NULL);
9709       MOVA (l);
9710       emitcode ("rlc", "a");
9711       aopPut (result, "a", offset++);
9712     }
9713   _endLazyDPSEvaluation ();
9714   reAdjustPreg (AOP (result));
9715
9716   emitLabel (tlbl1);
9717   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9718   popB (pushedB);
9719 release:
9720   freeAsmop (result, NULL, ic, TRUE);
9721   freeAsmop (left, NULL, ic, TRUE);
9722 }
9723
9724 #ifdef BETTER_LITERAL_SHIFT
9725 /*-----------------------------------------------------------------*/
9726 /* genrshOne - right shift a one byte quantity by known count      */
9727 /*-----------------------------------------------------------------*/
9728 static void
9729 genrshOne (operand * result, operand * left,
9730            int shCount, int sign)
9731 {
9732   D (emitcode (";", "genrshOne"));
9733
9734   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9735 }
9736 #endif
9737
9738 #ifdef BETTER_LITERAL_SHIFT
9739 /*-----------------------------------------------------------------*/
9740 /* genrshTwo - right shift two bytes by known amount != 0          */
9741 /*-----------------------------------------------------------------*/
9742 static void
9743 genrshTwo (operand * result, operand * left,
9744            int shCount, int sign)
9745 {
9746   D (emitcode (";", "genrshTwo"));
9747
9748   /* if shCount >= 8 */
9749   if (shCount >= 8)
9750     {
9751       shCount -= 8;
9752       _startLazyDPSEvaluation();
9753       if (shCount)
9754         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9755       else
9756         movLeft2Result (left, MSB16, result, LSB, sign);
9757       addSign (result, MSB16, sign);
9758       _endLazyDPSEvaluation();
9759     }
9760
9761   /*  1 <= shCount <= 7 */
9762   else
9763     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9764 }
9765 #endif
9766
9767 /*-----------------------------------------------------------------*/
9768 /* shiftRLong - shift right one long from left to result           */
9769 /* offl = LSB or MSB16                                             */
9770 /*-----------------------------------------------------------------*/
9771 static void
9772 shiftRLong (operand * left, int offl,
9773             operand * result, int sign)
9774 {
9775   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9776
9777   if (overlapping && offl>1)
9778     {
9779       // we are in big trouble, but this shouldn't happen
9780       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9781     }
9782
9783   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9784
9785   if (offl==MSB16)
9786     {
9787       // shift is > 8
9788       if (sign)
9789         {
9790           emitcode ("rlc", "a");
9791           emitcode ("subb", "a,acc");
9792           emitcode ("xch", "a,%s",
9793                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9794         }
9795       else
9796         {
9797           aopPut (result, zero, MSB32);
9798         }
9799     }
9800
9801   if (!sign)
9802     {
9803       emitcode ("clr", "c");
9804     }
9805   else
9806     {
9807       emitcode ("mov", "c,acc.7");
9808     }
9809
9810   emitcode ("rrc", "a");
9811
9812   if (overlapping && offl==MSB16)
9813     {
9814       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9815     }
9816   else
9817     {
9818       aopPut (result, "a", MSB32 - offl);
9819       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9820     }
9821
9822   emitcode ("rrc", "a");
9823
9824   if (overlapping && offl==MSB16)
9825     {
9826       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9827     }
9828   else
9829     {
9830       aopPut (result, "a", MSB24 - offl);
9831       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9832     }
9833
9834   emitcode ("rrc", "a");
9835   if (offl != LSB)
9836     {
9837       aopPut (result, "a", MSB16 - offl);
9838     }
9839   else
9840     {
9841       if (overlapping && offl==MSB16)
9842         {
9843           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9844         }
9845       else
9846         {
9847           aopPut (result, "a", MSB16 - offl);
9848           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9849         }
9850       emitcode ("rrc", "a");
9851       aopPut (result, "a", LSB);
9852     }
9853 }
9854
9855 /*-----------------------------------------------------------------*/
9856 /* genrshFour - shift four byte by a known amount != 0             */
9857 /*-----------------------------------------------------------------*/
9858 static void
9859 genrshFour (operand * result, operand * left,
9860             int shCount, int sign)
9861 {
9862   D (emitcode (";", "genrshFour"));
9863
9864   /* if shifting more that 3 bytes */
9865   if (shCount >= 24)
9866     {
9867       shCount -= 24;
9868       _startLazyDPSEvaluation();
9869       if (shCount)
9870         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9871       else
9872         movLeft2Result (left, MSB32, result, LSB, sign);
9873       addSign (result, MSB16, sign);
9874       _endLazyDPSEvaluation();
9875     }
9876   else if (shCount >= 16)
9877     {
9878       shCount -= 16;
9879       _startLazyDPSEvaluation();
9880       if (shCount)
9881         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9882       else
9883         {
9884           movLeft2Result (left, MSB24, result, LSB, 0);
9885           movLeft2Result (left, MSB32, result, MSB16, sign);
9886         }
9887       addSign (result, MSB24, sign);
9888       _endLazyDPSEvaluation();
9889     }
9890   else if (shCount >= 8)
9891     {
9892       shCount -= 8;
9893       _startLazyDPSEvaluation();
9894       if (shCount == 1)
9895         {
9896           shiftRLong (left, MSB16, result, sign);
9897         }
9898       else if (shCount == 0)
9899         {
9900           movLeft2Result (left, MSB16, result, LSB, 0);
9901           movLeft2Result (left, MSB24, result, MSB16, 0);
9902           movLeft2Result (left, MSB32, result, MSB24, sign);
9903           addSign (result, MSB32, sign);
9904         }
9905       else
9906         {
9907           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9908           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9909           /* the last shift is signed */
9910           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9911           addSign (result, MSB32, sign);
9912         }
9913         _endLazyDPSEvaluation();
9914     }
9915   else
9916     {
9917       /* 1 <= shCount <= 7 */
9918       if (shCount <= 2)
9919         {
9920           shiftRLong (left, LSB, result, sign);
9921           if (shCount == 2)
9922             shiftRLong (result, LSB, result, sign);
9923         }
9924       else
9925         {
9926           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9927           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9928           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9929         }
9930     }
9931 }
9932
9933 #ifdef BETTER_LITERAL_SHIFT
9934 /*-----------------------------------------------------------------*/
9935 /* genRightShiftLiteral - right shifting by known count            */
9936 /*-----------------------------------------------------------------*/
9937 static bool
9938 genRightShiftLiteral (operand * left,
9939                       operand * right,
9940                       operand * result,
9941                       iCode * ic,
9942                       int sign)
9943 {
9944   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9945   int size;
9946
9947   size = getSize (operandType (result));
9948
9949   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9950
9951   /* We only handle certain easy cases so far. */
9952   if ((shCount != 0)
9953    && (shCount < (size * 8))
9954    && (size != 1)
9955    && (size != 2)
9956    && (size != 4))
9957   {
9958       D(emitcode (";", "genRightShiftLiteral wimping out"););
9959       return FALSE;
9960   }
9961
9962   freeAsmop (right, NULL, ic, TRUE);
9963
9964   aopOp (left, ic, FALSE, FALSE);
9965   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9966
9967 #if VIEW_SIZE
9968   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9969             AOP_SIZE (left));
9970 #endif
9971
9972   /* test the LEFT size !!! */
9973
9974   /* I suppose that the left size >= result size */
9975   if (shCount == 0)
9976   {
9977       size = getDataSize (result);
9978       _startLazyDPSEvaluation();
9979       while (size--)
9980         movLeft2Result (left, size, result, size, 0);
9981       _endLazyDPSEvaluation();
9982   }
9983   else if (shCount >= (size * 8))
9984     {
9985       if (sign)
9986         {
9987           /* get sign in acc.7 */
9988           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9989         }
9990       addSign (result, LSB, sign);
9991     }
9992   else
9993     {
9994       switch (size)
9995         {
9996         case 1:
9997           genrshOne (result, left, shCount, sign);
9998           break;
9999
10000         case 2:
10001           genrshTwo (result, left, shCount, sign);
10002           break;
10003 #if 1
10004         case 4:
10005           genrshFour (result, left, shCount, sign);
10006           break;
10007 #endif
10008         default:
10009           break;
10010         }
10011     }
10012   freeAsmop (result, NULL, ic, TRUE);
10013   freeAsmop (left, NULL, ic, TRUE);
10014
10015   return TRUE;
10016 }
10017 #endif
10018
10019 /*-----------------------------------------------------------------*/
10020 /* genSignedRightShift - right shift of signed number              */
10021 /*-----------------------------------------------------------------*/
10022 static void
10023 genSignedRightShift (iCode * ic)
10024 {
10025   operand *right, *left, *result;
10026   int size, offset;
10027   char *l;
10028   symbol *tlbl, *tlbl1;
10029   bool pushedB;
10030
10031   D (emitcode (";", "genSignedRightShift"));
10032
10033   /* we do it the hard way put the shift count in b
10034      and loop thru preserving the sign */
10035
10036   right = IC_RIGHT (ic);
10037   left = IC_LEFT (ic);
10038   result = IC_RESULT (ic);
10039
10040   aopOp (right, ic, FALSE, FALSE);
10041
10042 #ifdef BETTER_LITERAL_SHIFT
10043   if (AOP_TYPE (right) == AOP_LIT)
10044     {
10045       if (genRightShiftLiteral (left, right, result, ic, 1))
10046       {
10047         return;
10048       }
10049     }
10050 #endif
10051   /* shift count is unknown then we have to form
10052      a loop get the loop count in B : Note: we take
10053      only the lower order byte since shifting
10054      more that 32 bits make no sense anyway, ( the
10055      largest size of an object can be only 32 bits ) */
10056
10057   pushedB = pushB ();
10058   if (AOP_TYPE (right) == AOP_LIT)
10059   {
10060       /* Really should be handled by genRightShiftLiteral,
10061        * but since I'm too lazy to fix that today, at least we can make
10062        * some small improvement.
10063        */
10064        emitcode("mov", "b,#!constbyte",
10065                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10066   }
10067   else
10068   {
10069         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10070         emitcode ("inc", "b");
10071   }
10072   freeAsmop (right, NULL, ic, TRUE);
10073   aopOp (left, ic, FALSE, FALSE);
10074   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10075
10076   /* now move the left to the result if they are not the
10077      same */
10078   if (!sameRegs (AOP (left), AOP (result)) &&
10079       AOP_SIZE (result) > 1)
10080     {
10081
10082       size = AOP_SIZE (result);
10083       offset = 0;
10084       _startLazyDPSEvaluation ();
10085       while (size--)
10086         {
10087           l = aopGet (left, offset, FALSE, TRUE, NULL);
10088           if (*l == '@' && IS_AOP_PREG (result))
10089             {
10090
10091               emitcode ("mov", "a,%s", l);
10092               aopPut (result, "a", offset);
10093             }
10094           else
10095             aopPut (result, l, offset);
10096           offset++;
10097         }
10098       _endLazyDPSEvaluation ();
10099     }
10100
10101   /* mov the highest order bit to OVR */
10102   tlbl = newiTempLabel (NULL);
10103   tlbl1 = newiTempLabel (NULL);
10104
10105   size = AOP_SIZE (result);
10106   offset = size - 1;
10107   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10108   emitcode ("rlc", "a");
10109   emitcode ("mov", "ov,c");
10110   /* if it is only one byte then */
10111   if (size == 1)
10112     {
10113       l = aopGet (left, 0, FALSE, FALSE, NULL);
10114       MOVA (l);
10115       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10116       emitLabel (tlbl);
10117       emitcode ("mov", "c,ov");
10118       emitcode ("rrc", "a");
10119       emitLabel (tlbl1);
10120       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10121       popB (pushedB);
10122       aopPut (result, "a", 0);
10123       goto release;
10124     }
10125
10126   reAdjustPreg (AOP (result));
10127   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10128   emitLabel (tlbl);
10129   emitcode ("mov", "c,ov");
10130   _startLazyDPSEvaluation ();
10131   while (size--)
10132     {
10133       l = aopGet (result, offset, FALSE, FALSE, NULL);
10134       MOVA (l);
10135       emitcode ("rrc", "a");
10136       aopPut (result, "a", offset--);
10137     }
10138   _endLazyDPSEvaluation ();
10139   reAdjustPreg (AOP (result));
10140   emitLabel (tlbl1);
10141   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10142   popB (pushedB);
10143
10144 release:
10145   freeAsmop (result, NULL, ic, TRUE);
10146   freeAsmop (left, NULL, ic, TRUE);
10147 }
10148
10149 /*-----------------------------------------------------------------*/
10150 /* genRightShift - generate code for right shifting                */
10151 /*-----------------------------------------------------------------*/
10152 static void
10153 genRightShift (iCode * ic)
10154 {
10155   operand *right, *left, *result;
10156   sym_link *letype;
10157   int size, offset;
10158   char *l;
10159   symbol *tlbl, *tlbl1;
10160   bool pushedB;
10161
10162   D (emitcode (";", "genRightShift"));
10163
10164   /* if signed then we do it the hard way preserve the
10165      sign bit moving it inwards */
10166   letype = getSpec (operandType (IC_LEFT (ic)));
10167
10168   if (!SPEC_USIGN (letype))
10169     {
10170       genSignedRightShift (ic);
10171       return;
10172     }
10173
10174   /* signed & unsigned types are treated the same : i.e. the
10175      signed is NOT propagated inwards : quoting from the
10176      ANSI - standard : "for E1 >> E2, is equivalent to division
10177      by 2**E2 if unsigned or if it has a non-negative value,
10178      otherwise the result is implementation defined ", MY definition
10179      is that the sign does not get propagated */
10180
10181   right = IC_RIGHT (ic);
10182   left = IC_LEFT (ic);
10183   result = IC_RESULT (ic);
10184
10185   aopOp (right, ic, FALSE, FALSE);
10186
10187 #ifdef BETTER_LITERAL_SHIFT
10188   /* if the shift count is known then do it
10189      as efficiently as possible */
10190   if (AOP_TYPE (right) == AOP_LIT)
10191     {
10192       if (genRightShiftLiteral (left, right, result, ic, 0))
10193       {
10194         return;
10195       }
10196     }
10197 #endif
10198
10199   /* shift count is unknown then we have to form
10200      a loop get the loop count in B : Note: we take
10201      only the lower order byte since shifting
10202      more that 32 bits make no sense anyway, ( the
10203      largest size of an object can be only 32 bits ) */
10204
10205   pushedB = pushB ();
10206   if (AOP_TYPE (right) == AOP_LIT)
10207   {
10208       /* Really should be handled by genRightShiftLiteral,
10209        * but since I'm too lazy to fix that today, at least we can make
10210        * some small improvement.
10211        */
10212        emitcode("mov", "b,#!constbyte",
10213                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10214   }
10215   else
10216   {
10217       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10218       emitcode ("inc", "b");
10219   }
10220   freeAsmop (right, NULL, ic, TRUE);
10221   aopOp (left, ic, FALSE, FALSE);
10222   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10223
10224   /* now move the left to the result if they are not the
10225      same */
10226   if (!sameRegs (AOP (left), AOP (result)) &&
10227       AOP_SIZE (result) > 1)
10228     {
10229       size = AOP_SIZE (result);
10230       offset = 0;
10231       _startLazyDPSEvaluation ();
10232       while (size--)
10233         {
10234           l = aopGet (left, offset, FALSE, TRUE, NULL);
10235           if (*l == '@' && IS_AOP_PREG (result))
10236             {
10237
10238               emitcode ("mov", "a,%s", l);
10239               aopPut (result, "a", offset);
10240             }
10241           else
10242             aopPut (result, l, offset);
10243           offset++;
10244         }
10245       _endLazyDPSEvaluation ();
10246     }
10247
10248   tlbl = newiTempLabel (NULL);
10249   tlbl1 = newiTempLabel (NULL);
10250   size = AOP_SIZE (result);
10251   offset = size - 1;
10252
10253   /* if it is only one byte then */
10254   if (size == 1)
10255     {
10256       l = aopGet (left, 0, FALSE, FALSE, NULL);
10257       MOVA (l);
10258       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10259       emitLabel (tlbl);
10260       CLRC;
10261       emitcode ("rrc", "a");
10262       emitLabel (tlbl1);
10263       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10264       popB (pushedB);
10265       aopPut (result, "a", 0);
10266       goto release;
10267     }
10268
10269   reAdjustPreg (AOP (result));
10270   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10271   emitLabel (tlbl);
10272   CLRC;
10273   _startLazyDPSEvaluation ();
10274   while (size--)
10275     {
10276       l = aopGet (result, offset, FALSE, FALSE, NULL);
10277       MOVA (l);
10278       emitcode ("rrc", "a");
10279       aopPut (result, "a", offset--);
10280     }
10281   _endLazyDPSEvaluation ();
10282   reAdjustPreg (AOP (result));
10283
10284   emitLabel (tlbl1);
10285   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10286   popB (pushedB);
10287
10288 release:
10289   freeAsmop (result, NULL, ic, TRUE);
10290   freeAsmop (left, NULL, ic, TRUE);
10291 }
10292
10293 /*-----------------------------------------------------------------*/
10294 /* emitPtrByteGet - emits code to get a byte into A through a      */
10295 /*                  pointer register (R0, R1, or DPTR). The        */
10296 /*                  original value of A can be preserved in B.     */
10297 /*-----------------------------------------------------------------*/
10298 static void
10299 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10300 {
10301   switch (p_type)
10302     {
10303     case IPOINTER:
10304     case POINTER:
10305       if (preserveAinB)
10306         emitcode ("mov", "b,a");
10307       emitcode ("mov", "a,@%s", rname);
10308       break;
10309
10310     case PPOINTER:
10311       if (preserveAinB)
10312         emitcode ("mov", "b,a");
10313       emitcode ("movx", "a,@%s", rname);
10314       break;
10315
10316     case FPOINTER:
10317       if (preserveAinB)
10318         emitcode ("mov", "b,a");
10319       emitcode ("movx", "a,@dptr");
10320       break;
10321
10322     case CPOINTER:
10323       if (preserveAinB)
10324         emitcode ("mov", "b,a");
10325       emitcode ("clr", "a");
10326       emitcode ("movc", "a,@a+dptr");
10327       break;
10328
10329     case GPOINTER:
10330       if (preserveAinB)
10331         {
10332           emitcode ("push", "b");
10333           emitcode ("push", "acc");
10334         }
10335       emitcode ("lcall", "__gptrget");
10336       if (preserveAinB)
10337         emitcode ("pop", "b");
10338       break;
10339     }
10340 }
10341
10342 /*-----------------------------------------------------------------*/
10343 /* emitPtrByteSet - emits code to set a byte from src through a    */
10344 /*                  pointer register (R0, R1, or DPTR).            */
10345 /*-----------------------------------------------------------------*/
10346 static void
10347 emitPtrByteSet (char *rname, int p_type, char *src)
10348 {
10349   switch (p_type)
10350     {
10351     case IPOINTER:
10352     case POINTER:
10353       if (*src=='@')
10354         {
10355           MOVA (src);
10356           emitcode ("mov", "@%s,a", rname);
10357         }
10358       else
10359         emitcode ("mov", "@%s,%s", rname, src);
10360       break;
10361
10362     case PPOINTER:
10363       MOVA (src);
10364       emitcode ("movx", "@%s,a", rname);
10365       break;
10366
10367     case FPOINTER:
10368       MOVA (src);
10369       emitcode ("movx", "@dptr,a");
10370       break;
10371
10372     case GPOINTER:
10373       MOVA (src);
10374       emitcode ("lcall", "__gptrput");
10375       break;
10376     }
10377 }
10378
10379 /*-----------------------------------------------------------------*/
10380 /* genUnpackBits - generates code for unpacking bits               */
10381 /*-----------------------------------------------------------------*/
10382 static void
10383 genUnpackBits (operand * result, char *rname, int ptype)
10384 {
10385   int offset = 0;       /* result byte offset */
10386   int rsize;            /* result size */
10387   int rlen = 0;         /* remaining bitfield length */
10388   sym_link *etype;      /* bitfield type information */
10389   int blen;             /* bitfield length */
10390   int bstr;             /* bitfield starting bit within byte */
10391
10392   D(emitcode (";", "genUnpackBits"));
10393
10394   etype = getSpec (operandType (result));
10395   rsize = getSize (operandType (result));
10396   blen = SPEC_BLEN (etype);
10397   bstr = SPEC_BSTR (etype);
10398
10399   /* If the bitfield length is less than a byte */
10400   if (blen < 8)
10401     {
10402       emitPtrByteGet (rname, ptype, FALSE);
10403       AccRol (8 - bstr);
10404       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10405       if (!SPEC_USIGN (etype))
10406         {
10407           /* signed bitfield */
10408           symbol *tlbl = newiTempLabel (NULL);
10409
10410           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10411           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10412           emitLabel (tlbl);
10413         }
10414       aopPut (result, "a", offset++);
10415       goto finish;
10416     }
10417
10418   /* Bit field did not fit in a byte. Copy all
10419      but the partial byte at the end.  */
10420   for (rlen=blen;rlen>=8;rlen-=8)
10421     {
10422       emitPtrByteGet (rname, ptype, FALSE);
10423       aopPut (result, "a", offset++);
10424       if (rlen>8)
10425         emitcode ("inc", "%s", rname);
10426     }
10427
10428   /* Handle the partial byte at the end */
10429   if (rlen)
10430     {
10431       emitPtrByteGet (rname, ptype, FALSE);
10432       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10433       if (!SPEC_USIGN (etype))
10434         {
10435           /* signed bitfield */
10436           symbol *tlbl = newiTempLabel (NULL);
10437
10438           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10439           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10440           emitLabel (tlbl);
10441         }
10442       aopPut (result, "a", offset++);
10443     }
10444
10445 finish:
10446   if (offset < rsize)
10447     {
10448       char *source;
10449
10450       if (SPEC_USIGN (etype))
10451         source = zero;
10452       else
10453         {
10454           /* signed bitfield: sign extension with 0x00 or 0xff */
10455           emitcode ("rlc", "a");
10456           emitcode ("subb", "a,acc");
10457
10458           source = "a";
10459         }
10460       rsize -= offset;
10461       while (rsize--)
10462         aopPut (result, source, offset++);
10463     }
10464 }
10465
10466
10467 /*-----------------------------------------------------------------*/
10468 /* genDataPointerGet - generates code when ptr offset is known     */
10469 /*-----------------------------------------------------------------*/
10470 static void
10471 genDataPointerGet (operand * left,
10472                    operand * result,
10473                    iCode * ic)
10474 {
10475   char *l;
10476   char buffer[256];
10477   int size, offset = 0;
10478   aopOp (result, ic, TRUE, FALSE);
10479
10480   /* get the string representation of the name */
10481   l = aopGet (left, 0, FALSE, TRUE, NULL);
10482   size = AOP_SIZE (result);
10483   _startLazyDPSEvaluation ();
10484   while (size--)
10485     {
10486         if (offset)
10487         {
10488             SNPRINTF (buffer, sizeof(buffer),
10489                       "(%s + %d)", l + 1, offset);
10490         }
10491         else
10492         {
10493             SNPRINTF (buffer, sizeof(buffer),
10494                       "%s", l + 1);
10495         }
10496       aopPut (result, buffer, offset++);
10497     }
10498   _endLazyDPSEvaluation ();
10499
10500   freeAsmop (result, NULL, ic, TRUE);
10501   freeAsmop (left, NULL, ic, TRUE);
10502 }
10503
10504 /*-----------------------------------------------------------------*/
10505 /* genNearPointerGet - emitcode for near pointer fetch             */
10506 /*-----------------------------------------------------------------*/
10507 static void
10508 genNearPointerGet (operand * left,
10509                    operand * result,
10510                    iCode * ic,
10511                    iCode *pi)
10512 {
10513   asmop *aop = NULL;
10514   regs *preg;
10515   char *rname;
10516   sym_link *rtype, *retype, *letype;
10517   sym_link *ltype = operandType (left);
10518   char buffer[80];
10519
10520   rtype = operandType (result);
10521   retype = getSpec (rtype);
10522   letype = getSpec (ltype);
10523
10524   aopOp (left, ic, FALSE, FALSE);
10525
10526   /* if left is rematerialisable and
10527      result is not bitfield variable type and
10528      the left is pointer to data space i.e
10529      lower 128 bytes of space */
10530   if (AOP_TYPE (left) == AOP_IMMD &&
10531       !IS_BITFIELD (retype) &&
10532       !IS_BITFIELD (letype) &&
10533       DCL_TYPE (ltype) == POINTER)
10534     {
10535       genDataPointerGet (left, result, ic);
10536       return;
10537     }
10538
10539   /* if the value is already in a pointer register
10540      then don't need anything more */
10541   if (!AOP_INPREG (AOP (left)))
10542     {
10543       /* otherwise get a free pointer register */
10544       aop = newAsmop (0);
10545       preg = getFreePtr (ic, &aop, FALSE);
10546       emitcode ("mov", "%s,%s",
10547                 preg->name,
10548                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10549       rname = preg->name;
10550     }
10551   else
10552     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10553
10554   freeAsmop (left, NULL, ic, TRUE);
10555   aopOp (result, ic, FALSE, FALSE);
10556
10557   /* if bitfield then unpack the bits */
10558   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10559     genUnpackBits (result, rname, POINTER);
10560   else
10561     {
10562       /* we have can just get the values */
10563       int size = AOP_SIZE (result);
10564       int offset = 0;
10565
10566       while (size--)
10567         {
10568           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10569             {
10570
10571               emitcode ("mov", "a,@%s", rname);
10572               aopPut (result, "a", offset);
10573             }
10574           else
10575             {
10576               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10577               aopPut (result, buffer, offset);
10578             }
10579           offset++;
10580           if (size || pi)
10581             emitcode ("inc", "%s", rname);
10582         }
10583     }
10584
10585   /* now some housekeeping stuff */
10586   if (aop)      /* we had to allocate for this iCode */
10587     {
10588       if (pi) { /* post increment present */
10589         aopPut (left, rname, 0);
10590       }
10591       freeAsmop (NULL, aop, ic, TRUE);
10592     }
10593   else
10594     {
10595       /* we did not allocate which means left
10596          already in a pointer register, then
10597          if size > 0 && this could be used again
10598          we have to point it back to where it
10599          belongs */
10600       if (AOP_SIZE (result) > 1 &&
10601           !OP_SYMBOL (left)->remat &&
10602           (OP_SYMBOL (left)->liveTo > ic->seq ||
10603            ic->depth) &&
10604           !pi)
10605         {
10606           int size = AOP_SIZE (result) - 1;
10607           while (size--)
10608             emitcode ("dec", "%s", rname);
10609         }
10610     }
10611
10612   /* done */
10613   freeAsmop (result, NULL, ic, TRUE);
10614   if (pi) pi->generated = 1;
10615 }
10616
10617 /*-----------------------------------------------------------------*/
10618 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10619 /*-----------------------------------------------------------------*/
10620 static void
10621 genPagedPointerGet (operand * left,
10622                     operand * result,
10623                     iCode * ic,
10624                     iCode * pi)
10625 {
10626   asmop *aop = NULL;
10627   regs *preg;
10628   char *rname;
10629   sym_link *rtype, *retype, *letype;
10630
10631   rtype = operandType (result);
10632   retype = getSpec (rtype);
10633   letype = getSpec (operandType (left));
10634   aopOp (left, ic, FALSE, FALSE);
10635
10636   /* if the value is already in a pointer register
10637      then don't need anything more */
10638   if (!AOP_INPREG (AOP (left)))
10639     {
10640       /* otherwise get a free pointer register */
10641       aop = newAsmop (0);
10642       preg = getFreePtr (ic, &aop, FALSE);
10643       emitcode ("mov", "%s,%s",
10644                 preg->name,
10645                 aopGet (left, 0, FALSE, TRUE, NULL));
10646       rname = preg->name;
10647     }
10648   else
10649     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10650
10651   freeAsmop (left, NULL, ic, TRUE);
10652   aopOp (result, ic, FALSE, FALSE);
10653
10654   /* if bitfield then unpack the bits */
10655   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10656     genUnpackBits (result, rname, PPOINTER);
10657   else
10658     {
10659       /* we have can just get the values */
10660       int size = AOP_SIZE (result);
10661       int offset = 0;
10662
10663       while (size--)
10664         {
10665
10666           emitcode ("movx", "a,@%s", rname);
10667           aopPut (result, "a", offset);
10668
10669           offset++;
10670
10671           if (size || pi)
10672             emitcode ("inc", "%s", rname);
10673         }
10674     }
10675
10676   /* now some housekeeping stuff */
10677   if (aop)      /* we had to allocate for this iCode */
10678     {
10679       if (pi)
10680         aopPut (left, rname, 0);
10681       freeAsmop (NULL, aop, ic, TRUE);
10682     }
10683   else
10684     {
10685       /* we did not allocate which means left
10686          already in a pointer register, then
10687          if size > 0 && this could be used again
10688          we have to point it back to where it
10689          belongs */
10690       if (AOP_SIZE (result) > 1 &&
10691           !OP_SYMBOL (left)->remat &&
10692           (OP_SYMBOL (left)->liveTo > ic->seq ||
10693            ic->depth) &&
10694           !pi)
10695         {
10696           int size = AOP_SIZE (result) - 1;
10697           while (size--)
10698             emitcode ("dec", "%s", rname);
10699         }
10700     }
10701
10702   /* done */
10703   freeAsmop (result, NULL, ic, TRUE);
10704   if (pi) pi->generated = 1;
10705 }
10706
10707 /*-----------------------------------------------------------------*/
10708 /* genFarPointerGet - get value from far space                     */
10709 /*-----------------------------------------------------------------*/
10710 static void
10711 genFarPointerGet (operand * left,
10712                   operand * result, iCode * ic, iCode *pi)
10713 {
10714   int size, offset, dopi=1;
10715   sym_link *retype = getSpec (operandType (result));
10716   sym_link *letype = getSpec (operandType (left));
10717   D (emitcode (";", "genFarPointerGet"););
10718
10719   aopOp (left, ic, FALSE, FALSE);
10720
10721   /* if the operand is already in dptr
10722      then we do nothing else we move the value to dptr */
10723   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10724     {
10725       /* if this is rematerializable */
10726       if (AOP_TYPE (left) == AOP_IMMD)
10727         {
10728           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10729         }
10730       else
10731         {
10732           /* we need to get it byte by byte */
10733           _startLazyDPSEvaluation ();
10734           if (AOP_TYPE (left) != AOP_DPTR)
10735             {
10736               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10737               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10738               if (options.model == MODEL_FLAT24)
10739                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10740             }
10741           else
10742             {
10743               /* We need to generate a load to DPTR indirect through DPTR. */
10744               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10745               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10746               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10747               if (options.model == MODEL_FLAT24)
10748                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10749               emitcode ("pop", "dph");
10750               emitcode ("pop", "dpl");
10751               dopi =0;
10752             }
10753           _endLazyDPSEvaluation ();
10754         }
10755     }
10756   /* so dptr now contains the address */
10757   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10758
10759   /* if bit then unpack */
10760   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10761       if (AOP_INDPTRn(left)) {
10762           genSetDPTR(AOP(left)->aopu.dptr);
10763       }
10764       genUnpackBits (result, "dptr", FPOINTER);
10765       if (AOP_INDPTRn(left)) {
10766           genSetDPTR(0);
10767       }
10768   } else
10769     {
10770       size = AOP_SIZE (result);
10771       offset = 0;
10772
10773       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10774           while (size--) {
10775               genSetDPTR(AOP(left)->aopu.dptr);
10776               emitcode ("movx", "a,@dptr");
10777               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10778                   emitcode ("inc", "dptr");
10779               genSetDPTR (0);
10780               aopPut (result, "a", offset++);
10781           }
10782       } else {
10783           _startLazyDPSEvaluation ();
10784           while (size--) {
10785               if (AOP_INDPTRn(left)) {
10786                   genSetDPTR(AOP(left)->aopu.dptr);
10787               } else {
10788                   genSetDPTR (0);
10789               }
10790               _flushLazyDPS ();
10791
10792               emitcode ("movx", "a,@dptr");
10793               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10794                   emitcode ("inc", "dptr");
10795
10796               aopPut (result, "a", offset++);
10797           }
10798           _endLazyDPSEvaluation ();
10799       }
10800     }
10801   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10802       if (!AOP_INDPTRn(left)) {
10803           _startLazyDPSEvaluation ();
10804           aopPut (left, "dpl", 0);
10805           aopPut (left, "dph", 1);
10806           if (options.model == MODEL_FLAT24)
10807               aopPut (left, "dpx", 2);
10808           _endLazyDPSEvaluation ();
10809       }
10810     pi->generated = 1;
10811   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10812              AOP_SIZE(result) > 1 &&
10813              IS_SYMOP(left) &&
10814              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10815
10816       size = AOP_SIZE (result) - 1;
10817       if (AOP_INDPTRn(left)) {
10818           genSetDPTR(AOP(left)->aopu.dptr);
10819       }
10820       while (size--) emitcode ("lcall","__decdptr");
10821       if (AOP_INDPTRn(left)) {
10822           genSetDPTR(0);
10823       }
10824   }
10825
10826   freeAsmop (result, NULL, ic, TRUE);
10827   freeAsmop (left, NULL, ic, TRUE);
10828 }
10829
10830 /*-----------------------------------------------------------------*/
10831 /* genCodePointerGet - get value from code space                   */
10832 /*-----------------------------------------------------------------*/
10833 static void
10834 genCodePointerGet (operand * left,
10835                     operand * result, iCode * ic, iCode *pi)
10836 {
10837   int size, offset, dopi=1;
10838   sym_link *retype = getSpec (operandType (result));
10839
10840   aopOp (left, ic, FALSE, FALSE);
10841
10842   /* if the operand is already in dptr
10843      then we do nothing else we move the value to dptr */
10844   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10845     {
10846       /* if this is rematerializable */
10847       if (AOP_TYPE (left) == AOP_IMMD)
10848         {
10849           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10850         }
10851       else
10852         {                       /* we need to get it byte by byte */
10853           _startLazyDPSEvaluation ();
10854           if (AOP_TYPE (left) != AOP_DPTR)
10855             {
10856               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10857               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10858               if (options.model == MODEL_FLAT24)
10859                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10860             }
10861           else
10862             {
10863               /* We need to generate a load to DPTR indirect through DPTR. */
10864               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10865               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10866               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10867               if (options.model == MODEL_FLAT24)
10868                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10869               emitcode ("pop", "dph");
10870               emitcode ("pop", "dpl");
10871               dopi=0;
10872             }
10873           _endLazyDPSEvaluation ();
10874         }
10875     }
10876   /* so dptr now contains the address */
10877   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10878
10879   /* if bit then unpack */
10880   if (IS_BITFIELD (retype)) {
10881       if (AOP_INDPTRn(left)) {
10882           genSetDPTR(AOP(left)->aopu.dptr);
10883       }
10884       genUnpackBits (result, "dptr", CPOINTER);
10885       if (AOP_INDPTRn(left)) {
10886           genSetDPTR(0);
10887       }
10888   } else
10889     {
10890       size = AOP_SIZE (result);
10891       offset = 0;
10892       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10893           while (size--) {
10894               genSetDPTR(AOP(left)->aopu.dptr);
10895               emitcode ("clr", "a");
10896               emitcode ("movc", "a,@a+dptr");
10897               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10898                   emitcode ("inc", "dptr");
10899               genSetDPTR (0);
10900               aopPut (result, "a", offset++);
10901           }
10902       } else {
10903           _startLazyDPSEvaluation ();
10904           while (size--)
10905               {
10906                   if (AOP_INDPTRn(left)) {
10907                       genSetDPTR(AOP(left)->aopu.dptr);
10908                   } else {
10909                       genSetDPTR (0);
10910                   }
10911                   _flushLazyDPS ();
10912
10913                   emitcode ("clr", "a");
10914                   emitcode ("movc", "a,@a+dptr");
10915                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10916                       emitcode ("inc", "dptr");
10917                   aopPut (result, "a", offset++);
10918               }
10919           _endLazyDPSEvaluation ();
10920       }
10921     }
10922   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10923       if (!AOP_INDPTRn(left)) {
10924           _startLazyDPSEvaluation ();
10925
10926           aopPut (left, "dpl", 0);
10927           aopPut (left, "dph", 1);
10928           if (options.model == MODEL_FLAT24)
10929               aopPut (left, "dpx", 2);
10930
10931           _endLazyDPSEvaluation ();
10932       }
10933       pi->generated = 1;
10934   } else if (IS_SYMOP(left) &&
10935              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10936              AOP_SIZE(result) > 1 &&
10937              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10938
10939       size = AOP_SIZE (result) - 1;
10940       if (AOP_INDPTRn(left)) {
10941           genSetDPTR(AOP(left)->aopu.dptr);
10942       }
10943       while (size--) emitcode ("lcall","__decdptr");
10944       if (AOP_INDPTRn(left)) {
10945           genSetDPTR(0);
10946       }
10947   }
10948
10949   freeAsmop (result, NULL, ic, TRUE);
10950   freeAsmop (left, NULL, ic, TRUE);
10951 }
10952
10953 /*-----------------------------------------------------------------*/
10954 /* genGenPointerGet - get value from generic pointer space         */
10955 /*-----------------------------------------------------------------*/
10956 static void
10957 genGenPointerGet (operand * left,
10958                   operand * result, iCode * ic, iCode * pi)
10959 {
10960   int size, offset;
10961   bool pushedB;
10962   sym_link *retype = getSpec (operandType (result));
10963   sym_link *letype = getSpec (operandType (left));
10964
10965   D (emitcode (";", "genGenPointerGet"));
10966
10967   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10968
10969   pushedB = pushB ();
10970   /* if the operand is already in dptr
10971      then we do nothing else we move the value to dptr */
10972   if (AOP_TYPE (left) != AOP_STR)
10973     {
10974       /* if this is rematerializable */
10975       if (AOP_TYPE (left) == AOP_IMMD)
10976         {
10977           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10978           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10979             {
10980               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10981             }
10982           else
10983             {
10984               emitcode ("mov", "b,#%d", pointerCode (retype));
10985             }
10986         }
10987       else
10988         {                       /* we need to get it byte by byte */
10989           _startLazyDPSEvaluation ();
10990           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10991           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10992           if (options.model == MODEL_FLAT24) {
10993               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10994               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10995           } else {
10996               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10997           }
10998           _endLazyDPSEvaluation ();
10999         }
11000     }
11001
11002   /* so dptr-b now contains the address */
11003   aopOp (result, ic, FALSE, TRUE);
11004
11005   /* if bit then unpack */
11006   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11007   {
11008     genUnpackBits (result, "dptr", GPOINTER);
11009   }
11010   else
11011     {
11012         size = AOP_SIZE (result);
11013         offset = 0;
11014
11015         while (size--)
11016         {
11017             if (size)
11018             {
11019                 // Get two bytes at a time, results in _AP & A.
11020                 // dptr will be incremented ONCE by __gptrgetWord.
11021                 //
11022                 // Note: any change here must be coordinated
11023                 // with the implementation of __gptrgetWord
11024                 // in device/lib/_gptrget.c
11025                 emitcode ("lcall", "__gptrgetWord");
11026                 aopPut (result, "a", offset++);
11027                 aopPut (result, DP2_RESULT_REG, offset++);
11028                 size--;
11029             }
11030             else
11031             {
11032                 // Only one byte to get.
11033                 emitcode ("lcall", "__gptrget");
11034                 aopPut (result, "a", offset++);
11035             }
11036
11037             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11038             {
11039                 emitcode ("inc", "dptr");
11040             }
11041         }
11042     }
11043
11044   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11045     _startLazyDPSEvaluation ();
11046
11047     aopPut (left, "dpl", 0);
11048     aopPut (left, "dph", 1);
11049     if (options.model == MODEL_FLAT24) {
11050         aopPut (left, "dpx", 2);
11051         aopPut (left, "b", 3);
11052     } else  aopPut (left, "b", 2);
11053
11054     _endLazyDPSEvaluation ();
11055
11056     pi->generated = 1;
11057   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11058              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11059
11060       size = AOP_SIZE (result) - 1;
11061       while (size--) emitcode ("lcall","__decdptr");
11062   }
11063   popB (pushedB);
11064
11065   freeAsmop (result, NULL, ic, TRUE);
11066   freeAsmop (left, NULL, ic, TRUE);
11067 }
11068
11069 /*-----------------------------------------------------------------*/
11070 /* genPointerGet - generate code for pointer get                   */
11071 /*-----------------------------------------------------------------*/
11072 static void
11073 genPointerGet (iCode * ic, iCode *pi)
11074 {
11075   operand *left, *result;
11076   sym_link *type, *etype;
11077   int p_type;
11078
11079   D (emitcode (";", "genPointerGet"));
11080
11081   left = IC_LEFT (ic);
11082   result = IC_RESULT (ic);
11083
11084   /* depending on the type of pointer we need to
11085      move it to the correct pointer register */
11086   type = operandType (left);
11087   etype = getSpec (type);
11088   /* if left is of type of pointer then it is simple */
11089   if (IS_PTR (type) && !IS_FUNC (type->next))
11090     p_type = DCL_TYPE (type);
11091   else
11092     {
11093       /* we have to go by the storage class */
11094       p_type = PTR_TYPE (SPEC_OCLS (etype));
11095     }
11096
11097   /* special case when cast remat */
11098   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11099       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11100     {
11101       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11102       type = operandType (left);
11103       p_type = DCL_TYPE (type);
11104     }
11105   /* now that we have the pointer type we assign
11106      the pointer values */
11107   switch (p_type)
11108     {
11109
11110     case POINTER:
11111     case IPOINTER:
11112       genNearPointerGet (left, result, ic, pi);
11113       break;
11114
11115     case PPOINTER:
11116       genPagedPointerGet (left, result, ic, pi);
11117       break;
11118
11119     case FPOINTER:
11120       genFarPointerGet (left, result, ic, pi);
11121       break;
11122
11123     case CPOINTER:
11124       genCodePointerGet (left, result, ic, pi);
11125       break;
11126
11127     case GPOINTER:
11128       genGenPointerGet (left, result, ic, pi);
11129       break;
11130     }
11131 }
11132
11133
11134 /*-----------------------------------------------------------------*/
11135 /* genPackBits - generates code for packed bit storage             */
11136 /*-----------------------------------------------------------------*/
11137 static void
11138 genPackBits (sym_link * etype,
11139              operand * right,
11140              char *rname, int p_type)
11141 {
11142   int offset = 0;       /* source byte offset */
11143   int rlen = 0;         /* remaining bitfield length */
11144   int blen;             /* bitfield length */
11145   int bstr;             /* bitfield starting bit within byte */
11146   int litval;           /* source literal value (if AOP_LIT) */
11147   unsigned char mask;   /* bitmask within current byte */
11148
11149   D(emitcode (";", "genPackBits"));
11150
11151   blen = SPEC_BLEN (etype);
11152   bstr = SPEC_BSTR (etype);
11153
11154   /* If the bitfield length is less than a byte */
11155   if (blen < 8)
11156     {
11157       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11158               (unsigned char) (0xFF >> (8 - bstr)));
11159
11160       if (AOP_TYPE (right) == AOP_LIT)
11161         {
11162           /* Case with a bitfield length <8 and literal source
11163           */
11164           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11165           litval <<= bstr;
11166           litval &= (~mask) & 0xff;
11167           emitPtrByteGet (rname, p_type, FALSE);
11168           if ((mask|litval)!=0xff)
11169             emitcode ("anl","a,#!constbyte", mask);
11170           if (litval)
11171             emitcode ("orl","a,#!constbyte", litval);
11172         }
11173       else
11174         {
11175           if ((blen==1) && (p_type!=GPOINTER))
11176             {
11177               /* Case with a bitfield length == 1 and no generic pointer
11178               */
11179               if (AOP_TYPE (right) == AOP_CRY)
11180                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11181               else
11182                 {
11183                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11184                   emitcode ("rrc","a");
11185                 }
11186               emitPtrByteGet (rname, p_type, FALSE);
11187               emitcode ("mov","acc.%d,c",bstr);
11188             }
11189           else
11190             {
11191               bool pushedB;
11192               /* Case with a bitfield length < 8 and arbitrary source
11193               */
11194               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11195               /* shift and mask source value */
11196               AccLsh (bstr);
11197               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11198
11199               pushedB = pushB ();
11200               /* transfer A to B and get next byte */
11201               emitPtrByteGet (rname, p_type, TRUE);
11202
11203               emitcode ("anl", "a,#!constbyte", mask);
11204               emitcode ("orl", "a,b");
11205               if (p_type == GPOINTER)
11206                 emitcode ("pop", "b");
11207
11208               popB (pushedB);
11209            }
11210         }
11211
11212       emitPtrByteSet (rname, p_type, "a");
11213       return;
11214     }
11215
11216   /* Bit length is greater than 7 bits. In this case, copy  */
11217   /* all except the partial byte at the end                 */
11218   for (rlen=blen;rlen>=8;rlen-=8)
11219     {
11220       emitPtrByteSet (rname, p_type,
11221                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11222       if (rlen>8)
11223         emitcode ("inc", "%s", rname);
11224     }
11225
11226   /* If there was a partial byte at the end */
11227   if (rlen)
11228     {
11229       mask = (((unsigned char) -1 << rlen) & 0xff);
11230
11231       if (AOP_TYPE (right) == AOP_LIT)
11232         {
11233           /* Case with partial byte and literal source
11234           */
11235           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11236           litval >>= (blen-rlen);
11237           litval &= (~mask) & 0xff;
11238           emitPtrByteGet (rname, p_type, FALSE);
11239           if ((mask|litval)!=0xff)
11240             emitcode ("anl","a,#!constbyte", mask);
11241           if (litval)
11242             emitcode ("orl","a,#!constbyte", litval);
11243         }
11244       else
11245         {
11246           bool pushedB;
11247           /* Case with partial byte and arbitrary source
11248           */
11249           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11250           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11251
11252           pushedB = pushB ();
11253           /* transfer A to B and get next byte */
11254           emitPtrByteGet (rname, p_type, TRUE);
11255
11256           emitcode ("anl", "a,#!constbyte", mask);
11257           emitcode ("orl", "a,b");
11258           if (p_type == GPOINTER)
11259             emitcode ("pop", "b");
11260
11261           popB (pushedB);
11262         }
11263       emitPtrByteSet (rname, p_type, "a");
11264     }
11265 }
11266
11267
11268 /*-----------------------------------------------------------------*/
11269 /* genDataPointerSet - remat pointer to data space                 */
11270 /*-----------------------------------------------------------------*/
11271 static void
11272 genDataPointerSet (operand * right,
11273                    operand * result,
11274                    iCode * ic)
11275 {
11276   int size, offset = 0;
11277   char *l, buffer[256];
11278
11279   D (emitcode (";", "genDataPointerSet"));
11280
11281   aopOp (right, ic, FALSE, FALSE);
11282
11283   l = aopGet (result, 0, FALSE, TRUE, NULL);
11284   size = AOP_SIZE (right);
11285   while (size--)
11286     {
11287       if (offset)
11288           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11289       else
11290           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11291       emitcode ("mov", "%s,%s", buffer,
11292                 aopGet (right, offset++, FALSE, FALSE, NULL));
11293     }
11294
11295   freeAsmop (result, NULL, ic, TRUE);
11296   freeAsmop (right, NULL, ic, TRUE);
11297 }
11298
11299 /*-----------------------------------------------------------------*/
11300 /* genNearPointerSet - emitcode for near pointer put                */
11301 /*-----------------------------------------------------------------*/
11302 static void
11303 genNearPointerSet (operand * right,
11304                    operand * result,
11305                    iCode * ic,
11306                    iCode * pi)
11307 {
11308   asmop *aop = NULL;
11309   char *rname, *l;
11310   sym_link *retype, *letype;
11311   sym_link *ptype = operandType (result);
11312
11313   D (emitcode (";", "genNearPointerSet"));
11314
11315   retype = getSpec (operandType (right));
11316   letype = getSpec (ptype);
11317
11318   aopOp (result, ic, FALSE, FALSE);
11319
11320   /* if the result is rematerializable &
11321      in data space & not a bit variable */
11322   if (AOP_TYPE (result) == AOP_IMMD &&
11323       DCL_TYPE (ptype) == POINTER &&
11324       !IS_BITVAR (retype) &&
11325       !IS_BITVAR (letype))
11326     {
11327       genDataPointerSet (right, result, ic);
11328       return;
11329     }
11330
11331   /* if the value is already in a pointer register
11332      then don't need anything more */
11333   if (!AOP_INPREG (AOP (result)))
11334     {
11335       /* otherwise get a free pointer register */
11336       regs *preg;
11337
11338       aop = newAsmop (0);
11339       preg = getFreePtr (ic, &aop, FALSE);
11340       emitcode ("mov", "%s,%s",
11341                 preg->name,
11342                 aopGet (result, 0, FALSE, TRUE, NULL));
11343       rname = preg->name;
11344     }
11345   else
11346     {
11347       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11348     }
11349
11350   aopOp (right, ic, FALSE, FALSE);
11351
11352   /* if bitfield then unpack the bits */
11353   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11354     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11355   else
11356     {
11357       /* we can just get the values */
11358       int size = AOP_SIZE (right);
11359       int offset = 0;
11360
11361       while (size--)
11362         {
11363           l = aopGet (right, offset, FALSE, TRUE, NULL);
11364           if ((*l == '@') || (strcmp (l, "acc") == 0))
11365             {
11366               MOVA (l);
11367               emitcode ("mov", "@%s,a", rname);
11368             }
11369           else
11370             emitcode ("mov", "@%s,%s", rname, l);
11371           if (size || pi)
11372             emitcode ("inc", "%s", rname);
11373           offset++;
11374         }
11375     }
11376
11377   /* now some housekeeping stuff */
11378   if (aop)      /* we had to allocate for this iCode */
11379     {
11380       if (pi)
11381         aopPut (result, rname, 0);
11382       freeAsmop (NULL, aop, ic, TRUE);
11383     }
11384   else
11385     {
11386       /* we did not allocate which means left
11387          already in a pointer register, then
11388          if size > 0 && this could be used again
11389          we have to point it back to where it
11390          belongs */
11391       if (AOP_SIZE (right) > 1 &&
11392           !OP_SYMBOL (result)->remat &&
11393           (OP_SYMBOL (result)->liveTo > ic->seq ||
11394            ic->depth) &&
11395           !pi)
11396         {
11397           int size = AOP_SIZE (right) - 1;
11398           while (size--)
11399             emitcode ("dec", "%s", rname);
11400         }
11401     }
11402
11403   /* done */
11404   if (pi) pi->generated = 1;
11405   freeAsmop (result, NULL, ic, TRUE);
11406   freeAsmop (right, NULL, ic, TRUE);
11407 }
11408
11409 /*-----------------------------------------------------------------*/
11410 /* genPagedPointerSet - emitcode for Paged pointer put             */
11411 /*-----------------------------------------------------------------*/
11412 static void
11413 genPagedPointerSet (operand * right,
11414                     operand * result,
11415                     iCode * ic,
11416                     iCode *pi)
11417 {
11418   asmop *aop = NULL;
11419   char *rname, *l;
11420   sym_link *retype, *letype;
11421
11422   D (emitcode (";", "genPagedPointerSet"));
11423
11424   retype = getSpec (operandType (right));
11425   letype = getSpec (operandType (result));
11426
11427   aopOp (result, ic, FALSE, FALSE);
11428
11429   /* if the value is already in a pointer register
11430      then don't need anything more */
11431   if (!AOP_INPREG (AOP (result)))
11432     {
11433       /* otherwise get a free pointer register */
11434       regs *preg;
11435
11436       aop = newAsmop (0);
11437       preg = getFreePtr (ic, &aop, FALSE);
11438       emitcode ("mov", "%s,%s",
11439                 preg->name,
11440                 aopGet (result, 0, FALSE, TRUE, NULL));
11441       rname = preg->name;
11442     }
11443   else
11444     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11445
11446   aopOp (right, ic, FALSE, FALSE);
11447
11448   /* if bitfield then unpack the bits */
11449   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11450     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11451   else
11452     {
11453       /* we have can just get the values */
11454       int size = AOP_SIZE (right);
11455       int offset = 0;
11456
11457       while (size--)
11458         {
11459           l = aopGet (right, offset, FALSE, TRUE, NULL);
11460           MOVA (l);
11461           emitcode ("movx", "@%s,a", rname);
11462
11463           if (size || pi)
11464             emitcode ("inc", "%s", rname);
11465
11466           offset++;
11467         }
11468     }
11469
11470   /* now some housekeeping stuff */
11471   if (aop)
11472     {
11473       if (pi)
11474         aopPut (result, rname, 0);
11475       /* we had to allocate for this iCode */
11476       freeAsmop (NULL, aop, ic, TRUE);
11477     }
11478   else
11479     {
11480       /* we did not allocate which means left
11481          already in a pointer register, then
11482          if size > 0 && this could be used again
11483          we have to point it back to where it
11484          belongs */
11485       if (AOP_SIZE (right) > 1 &&
11486           !OP_SYMBOL (result)->remat &&
11487           (OP_SYMBOL (result)->liveTo > ic->seq ||
11488            ic->depth) &&
11489           !pi)
11490         {
11491           int size = AOP_SIZE (right) - 1;
11492           while (size--)
11493             emitcode ("dec", "%s", rname);
11494         }
11495     }
11496
11497   /* done */
11498   if (pi) pi->generated = 1;
11499   freeAsmop (result, NULL, ic, TRUE);
11500   freeAsmop (right, NULL, ic, TRUE);
11501 }
11502
11503 /*-----------------------------------------------------------------*/
11504 /* genFarPointerSet - set value from far space                     */
11505 /*-----------------------------------------------------------------*/
11506 static void
11507 genFarPointerSet (operand * right,
11508                   operand * result, iCode * ic, iCode *pi)
11509 {
11510   int size, offset, dopi=1;
11511   sym_link *retype = getSpec (operandType (right));
11512   sym_link *letype = getSpec (operandType (result));
11513
11514   aopOp (result, ic, FALSE, FALSE);
11515
11516   /* if the operand is already in dptr
11517      then we do nothing else we move the value to dptr */
11518   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11519     {
11520       /* if this is remateriazable */
11521       if (AOP_TYPE (result) == AOP_IMMD)
11522         emitcode ("mov", "dptr,%s",
11523                   aopGet (result, 0, TRUE, FALSE, NULL));
11524       else
11525         {
11526           /* we need to get it byte by byte */
11527           _startLazyDPSEvaluation ();
11528           if (AOP_TYPE (result) != AOP_DPTR)
11529             {
11530               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11531               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11532               if (options.model == MODEL_FLAT24)
11533                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11534             }
11535           else
11536             {
11537               /* We need to generate a load to DPTR indirect through DPTR. */
11538               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11539
11540               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11541               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11542               if (options.model == MODEL_FLAT24)
11543                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11544               emitcode ("pop", "dph");
11545               emitcode ("pop", "dpl");
11546               dopi=0;
11547             }
11548           _endLazyDPSEvaluation ();
11549         }
11550     }
11551   /* so dptr now contains the address */
11552   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11553
11554   /* if bit then unpack */
11555   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11556   {
11557       if (AOP_INDPTRn(result)) {
11558           genSetDPTR(AOP(result)->aopu.dptr);
11559       }
11560       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11561       if (AOP_INDPTRn(result)) {
11562           genSetDPTR(0);
11563       }
11564   } else {
11565       size = AOP_SIZE (right);
11566       offset = 0;
11567       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11568           while (size--) {
11569               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11570
11571               genSetDPTR(AOP(result)->aopu.dptr);
11572               emitcode ("movx", "@dptr,a");
11573               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11574                   emitcode ("inc", "dptr");
11575               genSetDPTR (0);
11576           }
11577       } else {
11578           _startLazyDPSEvaluation ();
11579           while (size--) {
11580               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11581
11582               if (AOP_INDPTRn(result)) {
11583                   genSetDPTR(AOP(result)->aopu.dptr);
11584               } else {
11585                   genSetDPTR (0);
11586               }
11587               _flushLazyDPS ();
11588
11589               emitcode ("movx", "@dptr,a");
11590               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11591                   emitcode ("inc", "dptr");
11592           }
11593           _endLazyDPSEvaluation ();
11594       }
11595   }
11596
11597   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11598       if (!AOP_INDPTRn(result)) {
11599           _startLazyDPSEvaluation ();
11600
11601           aopPut (result,"dpl",0);
11602           aopPut (result,"dph",1);
11603           if (options.model == MODEL_FLAT24)
11604               aopPut (result,"dpx",2);
11605
11606           _endLazyDPSEvaluation ();
11607       }
11608       pi->generated=1;
11609   } else if (IS_SYMOP (result) &&
11610              (OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11611              AOP_SIZE(right) > 1 &&
11612              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11613
11614       size = AOP_SIZE (right) - 1;
11615       if (AOP_INDPTRn(result)) {
11616           genSetDPTR(AOP(result)->aopu.dptr);
11617       }
11618       while (size--) emitcode ("lcall","__decdptr");
11619       if (AOP_INDPTRn(result)) {
11620           genSetDPTR(0);
11621       }
11622   }
11623   freeAsmop (result, NULL, ic, TRUE);
11624   freeAsmop (right, NULL, ic, TRUE);
11625 }
11626
11627 /*-----------------------------------------------------------------*/
11628 /* genGenPointerSet - set value from generic pointer space         */
11629 /*-----------------------------------------------------------------*/
11630 static void
11631 genGenPointerSet (operand * right,
11632                   operand * result, iCode * ic, iCode *pi)
11633 {
11634   int size, offset;
11635   bool pushedB;
11636   sym_link *retype = getSpec (operandType (right));
11637   sym_link *letype = getSpec (operandType (result));
11638
11639   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11640
11641   pushedB = pushB ();
11642   /* if the operand is already in dptr
11643      then we do nothing else we move the value to dptr */
11644   if (AOP_TYPE (result) != AOP_STR)
11645     {
11646       _startLazyDPSEvaluation ();
11647       /* if this is remateriazable */
11648       if (AOP_TYPE (result) == AOP_IMMD)
11649         {
11650           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11651           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11652           {
11653               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11654           }
11655           else
11656           {
11657               emitcode ("mov",
11658                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11659           }
11660         }
11661       else
11662         {                       /* we need to get it byte by byte */
11663           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11664           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11665           if (options.model == MODEL_FLAT24) {
11666             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11667             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11668           } else {
11669             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11670           }
11671         }
11672       _endLazyDPSEvaluation ();
11673     }
11674   /* so dptr + b now contains the address */
11675   aopOp (right, ic, FALSE, TRUE);
11676
11677   /* if bit then unpack */
11678   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11679     {
11680         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11681     }
11682   else
11683     {
11684         size = AOP_SIZE (right);
11685         offset = 0;
11686
11687         _startLazyDPSEvaluation ();
11688         while (size--)
11689         {
11690             if (size)
11691             {
11692                 // Set two bytes at a time, passed in _AP & A.
11693                 // dptr will be incremented ONCE by __gptrputWord.
11694                 //
11695                 // Note: any change here must be coordinated
11696                 // with the implementation of __gptrputWord
11697                 // in device/lib/_gptrput.c
11698                 emitcode("mov", "_ap, %s",
11699                          aopGet (right, offset++, FALSE, FALSE, NULL));
11700                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11701
11702                 genSetDPTR (0);
11703                 _flushLazyDPS ();
11704                 emitcode ("lcall", "__gptrputWord");
11705                 size--;
11706             }
11707             else
11708             {
11709                 // Only one byte to put.
11710                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11711
11712                 genSetDPTR (0);
11713                 _flushLazyDPS ();
11714                 emitcode ("lcall", "__gptrput");
11715             }
11716
11717             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11718             {
11719                 emitcode ("inc", "dptr");
11720             }
11721         }
11722         _endLazyDPSEvaluation ();
11723     }
11724
11725   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11726       _startLazyDPSEvaluation ();
11727
11728       aopPut (result, "dpl",0);
11729       aopPut (result, "dph",1);
11730       if (options.model == MODEL_FLAT24) {
11731           aopPut (result, "dpx",2);
11732           aopPut (result, "b",3);
11733       } else {
11734           aopPut (result, "b",2);
11735       }
11736       _endLazyDPSEvaluation ();
11737
11738       pi->generated=1;
11739   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11740              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11741
11742       size = AOP_SIZE (right) - 1;
11743       while (size--) emitcode ("lcall","__decdptr");
11744   }
11745   popB (pushedB);
11746
11747   freeAsmop (result, NULL, ic, TRUE);
11748   freeAsmop (right, NULL, ic, TRUE);
11749 }
11750
11751 /*-----------------------------------------------------------------*/
11752 /* genPointerSet - stores the value into a pointer location        */
11753 /*-----------------------------------------------------------------*/
11754 static void
11755 genPointerSet (iCode * ic, iCode *pi)
11756 {
11757   operand *right, *result;
11758   sym_link *type, *etype;
11759   int p_type;
11760
11761   D (emitcode (";", "genPointerSet"));
11762
11763   right = IC_RIGHT (ic);
11764   result = IC_RESULT (ic);
11765
11766   /* depending on the type of pointer we need to
11767      move it to the correct pointer register */
11768   type = operandType (result);
11769   etype = getSpec (type);
11770   /* if left is of type of pointer then it is simple */
11771   if (IS_PTR (type) && !IS_FUNC (type->next))
11772     {
11773       p_type = DCL_TYPE (type);
11774     }
11775   else
11776     {
11777       /* we have to go by the storage class */
11778       p_type = PTR_TYPE (SPEC_OCLS (etype));
11779     }
11780
11781   /* special case when cast remat */
11782   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11783       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11784           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11785           type = operandType (result);
11786           p_type = DCL_TYPE (type);
11787   }
11788
11789   /* now that we have the pointer type we assign
11790      the pointer values */
11791   switch (p_type)
11792     {
11793
11794     case POINTER:
11795     case IPOINTER:
11796       genNearPointerSet (right, result, ic, pi);
11797       break;
11798
11799     case PPOINTER:
11800       genPagedPointerSet (right, result, ic, pi);
11801       break;
11802
11803     case FPOINTER:
11804       genFarPointerSet (right, result, ic, pi);
11805       break;
11806
11807     case GPOINTER:
11808       genGenPointerSet (right, result, ic, pi);
11809       break;
11810
11811     default:
11812       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11813               "genPointerSet: illegal pointer type");
11814     }
11815 }
11816
11817 /*-----------------------------------------------------------------*/
11818 /* genIfx - generate code for Ifx statement                        */
11819 /*-----------------------------------------------------------------*/
11820 static void
11821 genIfx (iCode * ic, iCode * popIc)
11822 {
11823   operand *cond = IC_COND (ic);
11824   int isbit = 0;
11825   char *dup = NULL;
11826
11827   D (emitcode (";", "genIfx"));
11828
11829   aopOp (cond, ic, FALSE, FALSE);
11830
11831   /* get the value into acc */
11832   if (AOP_TYPE (cond) != AOP_CRY)
11833     {
11834       toBoolean (cond);
11835     }
11836   else
11837     {
11838       isbit = 1;
11839       if (AOP(cond)->aopu.aop_dir)
11840         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11841     }
11842
11843   /* the result is now in the accumulator or a directly addressable bit */
11844   freeAsmop (cond, NULL, ic, TRUE);
11845
11846   /* if there was something to be popped then do it */
11847   if (popIc)
11848     genIpop (popIc);
11849
11850   /* if the condition is a bit variable */
11851   if (isbit && dup)
11852     genIfxJump (ic, dup);
11853   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11854     genIfxJump (ic, SPIL_LOC (cond)->rname);
11855   else if (isbit && !IS_ITEMP (cond))
11856     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11857   else
11858     genIfxJump (ic, "a");
11859
11860   ic->generated = 1;
11861 }
11862
11863 /*-----------------------------------------------------------------*/
11864 /* genAddrOf - generates code for address of                       */
11865 /*-----------------------------------------------------------------*/
11866 static void
11867 genAddrOf (iCode * ic)
11868 {
11869   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11870   int size, offset;
11871
11872   D (emitcode (";", "genAddrOf"));
11873
11874   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11875
11876   /* if the operand is on the stack then we
11877      need to get the stack offset of this
11878      variable */
11879   if (sym->onStack)
11880   {
11881
11882       /* if 10 bit stack */
11883       if (options.stack10bit) {
11884           char buff[10];
11885           int  offset;
11886
11887           tsprintf(buff, sizeof(buff),
11888                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11889           /* if it has an offset then we need to compute it */
11890 /*        emitcode ("subb", "a,#!constbyte", */
11891 /*                  -((sym->stack < 0) ? */
11892 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11893 /*                    ((short) sym->stack)) & 0xff); */
11894 /*        emitcode ("mov","b,a"); */
11895 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11896 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11897 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11898           if (sym->stack) {
11899               emitcode ("mov", "a,_bpx");
11900               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11901                                              ((char) (sym->stack - _G.nRegsSaved)) :
11902                                              ((char) sym->stack )) & 0xff);
11903               emitcode ("mov", "b,a");
11904               emitcode ("mov", "a,_bpx+1");
11905
11906               offset = (((sym->stack < 0) ?
11907                          ((short) (sym->stack - _G.nRegsSaved)) :
11908                          ((short) sym->stack )) >> 8) & 0xff;
11909
11910               emitcode ("addc","a,#!constbyte", offset);
11911
11912               aopPut (IC_RESULT (ic), "b", 0);
11913               aopPut (IC_RESULT (ic), "a", 1);
11914               aopPut (IC_RESULT (ic), buff, 2);
11915           } else {
11916               /* we can just move _bp */
11917               aopPut (IC_RESULT (ic), "_bpx", 0);
11918               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11919               aopPut (IC_RESULT (ic), buff, 2);
11920           }
11921       } else {
11922           /* if it has an offset then we need to compute it */
11923           if (sym->stack)
11924             {
11925               emitcode ("mov", "a,_bp");
11926               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11927               aopPut (IC_RESULT (ic), "a", 0);
11928             }
11929           else
11930             {
11931               /* we can just move _bp */
11932               aopPut (IC_RESULT (ic), "_bp", 0);
11933             }
11934           /* fill the result with zero */
11935           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11936
11937
11938           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11939               fprintf (stderr,
11940                        "*** warning: pointer to stack var truncated.\n");
11941           }
11942
11943           offset = 1;
11944           while (size--)
11945             {
11946               aopPut (IC_RESULT (ic), zero, offset++);
11947             }
11948       }
11949       goto release;
11950   }
11951
11952   /* object not on stack then we need the name */
11953   size = getDataSize (IC_RESULT (ic));
11954   offset = 0;
11955
11956   while (size--)
11957     {
11958       char s[SDCC_NAME_MAX];
11959       if (offset)
11960         {
11961           switch (offset) {
11962           case 1:
11963               tsprintf(s, sizeof(s), "#!his",sym->rname);
11964               break;
11965           case 2:
11966               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11967               break;
11968           case 3:
11969               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11970               break;
11971           default: /* should not need this (just in case) */
11972               SNPRINTF (s, sizeof(s), "#(%s >> %d)", sym->rname, offset * 8);
11973           }
11974       }
11975       else
11976       {
11977           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11978       }
11979
11980       aopPut (IC_RESULT (ic), s, offset++);
11981     }
11982   if (opIsGptr (IC_RESULT (ic)))
11983     {
11984       char buffer[10];
11985       SNPRINTF (buffer, sizeof(buffer), "#0x%02x",
11986                 pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
11987       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
11988     }
11989
11990 release:
11991   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11992
11993 }
11994
11995 #if 0 // obsolete, and buggy for != xdata
11996 /*-----------------------------------------------------------------*/
11997 /* genArrayInit - generates code for address of                       */
11998 /*-----------------------------------------------------------------*/
11999 static void
12000 genArrayInit (iCode * ic)
12001 {
12002     literalList *iLoop;
12003     int         ix, count;
12004     int         elementSize = 0, eIndex;
12005     unsigned    val, lastVal;
12006     sym_link    *type;
12007     operand     *left=IC_LEFT(ic);
12008
12009     D (emitcode (";", "genArrayInit"));
12010
12011     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
12012
12013     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
12014     {
12015         // Load immediate value into DPTR.
12016         emitcode("mov", "dptr, %s",
12017              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
12018     }
12019     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
12020     {
12021 #if 0
12022       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12023               "Unexpected operand to genArrayInit.\n");
12024       exit(1);
12025 #else
12026       // a regression because of SDCCcse.c:1.52
12027       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12028       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12029       if (options.model == MODEL_FLAT24)
12030         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12031 #endif
12032     }
12033
12034     type = operandType(IC_LEFT(ic));
12035
12036     if (type && type->next)
12037     {
12038         elementSize = getSize(type->next);
12039     }
12040     else
12041     {
12042         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12043                                 "can't determine element size in genArrayInit.\n");
12044         exit(1);
12045     }
12046
12047     iLoop = IC_ARRAYILIST(ic);
12048     lastVal = 0xffff;
12049
12050     while (iLoop)
12051     {
12052         bool firstpass = TRUE;
12053
12054         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12055                  iLoop->count, (int)iLoop->literalValue, elementSize);
12056
12057         ix = iLoop->count;
12058
12059         while (ix)
12060         {
12061             symbol *tlbl = NULL;
12062
12063             count = ix > 256 ? 256 : ix;
12064
12065             if (count > 1)
12066             {
12067                 tlbl = newiTempLabel (NULL);
12068                 if (firstpass || (count & 0xff))
12069                 {
12070                     emitcode("mov", "b, #!constbyte", count & 0xff);
12071                 }
12072
12073                 emitLabel (tlbl);
12074             }
12075
12076             firstpass = FALSE;
12077
12078             for (eIndex = 0; eIndex < elementSize; eIndex++)
12079             {
12080                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12081                 if (val != lastVal)
12082                 {
12083                     emitcode("mov", "a, #!constbyte", val);
12084                     lastVal = val;
12085                 }
12086
12087                 emitcode("movx", "@dptr, a");
12088                 emitcode("inc", "dptr");
12089             }
12090
12091             if (count > 1)
12092             {
12093                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12094             }
12095
12096             ix -= count;
12097         }
12098
12099         iLoop = iLoop->next;
12100     }
12101
12102     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12103 }
12104 #endif
12105
12106 /*-----------------------------------------------------------------*/
12107 /* genFarFarAssign - assignment when both are in far space         */
12108 /*-----------------------------------------------------------------*/
12109 static void
12110 genFarFarAssign (operand * result, operand * right, iCode * ic)
12111 {
12112   int size = AOP_SIZE (right);
12113   int offset = 0;
12114   symbol *rSym = NULL;
12115
12116   if (size == 1)
12117   {
12118       /* quick & easy case. */
12119       D (emitcode(";","genFarFarAssign (1 byte case)"));
12120       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12121       freeAsmop (right, NULL, ic, FALSE);
12122       /* now assign DPTR to result */
12123       _G.accInUse++;
12124       aopOp(result, ic, FALSE, FALSE);
12125       _G.accInUse--;
12126       aopPut (result, "a", 0);
12127       freeAsmop(result, NULL, ic, FALSE);
12128       return;
12129   }
12130
12131   /* See if we've got an underlying symbol to abuse. */
12132   if (IS_SYMOP(result) && OP_SYMBOL(result))
12133   {
12134       if (IS_TRUE_SYMOP(result))
12135       {
12136           rSym = OP_SYMBOL(result);
12137       }
12138       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12139       {
12140           rSym = OP_SYMBOL(result)->usl.spillLoc;
12141       }
12142   }
12143
12144   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12145   {
12146       /* We can use the '390 auto-toggle feature to good effect here. */
12147
12148       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12149       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12150       emitcode ("mov", "dptr,#%s", rSym->rname);
12151       /* DP2 = result, DP1 = right, DP1 is current. */
12152       while (size)
12153       {
12154           emitcode("movx", "a,@dptr");
12155           emitcode("movx", "@dptr,a");
12156           if (--size)
12157           {
12158                emitcode("inc", "dptr");
12159                emitcode("inc", "dptr");
12160           }
12161       }
12162       emitcode("mov", "dps,#0");
12163       freeAsmop (right, NULL, ic, FALSE);
12164 #if 0
12165 some alternative code for processors without auto-toggle
12166 no time to test now, so later well put in...kpb
12167         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12168         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12169         emitcode ("mov", "dptr,#%s", rSym->rname);
12170         /* DP2 = result, DP1 = right, DP1 is current. */
12171         while (size)
12172         {
12173           --size;
12174           emitcode("movx", "a,@dptr");
12175           if (size)
12176             emitcode("inc", "dptr");
12177           emitcode("inc", "dps");
12178           emitcode("movx", "@dptr,a");
12179           if (size)
12180             emitcode("inc", "dptr");
12181           emitcode("inc", "dps");
12182         }
12183         emitcode("mov", "dps,#0");
12184         freeAsmop (right, NULL, ic, FALSE);
12185 #endif
12186   }
12187   else
12188   {
12189       D (emitcode (";", "genFarFarAssign"));
12190       aopOp (result, ic, TRUE, TRUE);
12191
12192       _startLazyDPSEvaluation ();
12193
12194       while (size--)
12195         {
12196           aopPut (result,
12197                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12198           offset++;
12199         }
12200       _endLazyDPSEvaluation ();
12201       freeAsmop (result, NULL, ic, FALSE);
12202       freeAsmop (right, NULL, ic, FALSE);
12203   }
12204 }
12205
12206 /*-----------------------------------------------------------------*/
12207 /* genAssign - generate code for assignment                        */
12208 /*-----------------------------------------------------------------*/
12209 static void
12210 genAssign (iCode * ic)
12211 {
12212   operand *result, *right;
12213   int size, offset;
12214   unsigned long lit = 0L;
12215
12216   D (emitcode (";", "genAssign"));
12217
12218   result = IC_RESULT (ic);
12219   right = IC_RIGHT (ic);
12220
12221   /* if they are the same */
12222   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12223     return;
12224
12225   aopOp (right, ic, FALSE, FALSE);
12226
12227   emitcode (";", "genAssign: resultIsFar = %s",
12228             isOperandInFarSpace (result) ?
12229             "TRUE" : "FALSE");
12230
12231   /* special case both in far space */
12232   if ((AOP_TYPE (right) == AOP_DPTR ||
12233        AOP_TYPE (right) == AOP_DPTR2) &&
12234   /* IS_TRUE_SYMOP(result)       && */
12235       isOperandInFarSpace (result))
12236     {
12237       genFarFarAssign (result, right, ic);
12238       return;
12239     }
12240
12241   aopOp (result, ic, TRUE, FALSE);
12242
12243   /* if they are the same registers */
12244   if (sameRegs (AOP (right), AOP (result)))
12245     goto release;
12246
12247   /* if the result is a bit */
12248   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12249     {
12250       /* if the right size is a literal then
12251          we know what the value is */
12252       if (AOP_TYPE (right) == AOP_LIT)
12253         {
12254           if (((int) operandLitValue (right)))
12255             aopPut (result, one, 0);
12256           else
12257             aopPut (result, zero, 0);
12258           goto release;
12259         }
12260
12261       /* the right is also a bit variable */
12262       if (AOP_TYPE (right) == AOP_CRY)
12263         {
12264           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12265           aopPut (result, "c", 0);
12266           goto release;
12267         }
12268
12269       /* we need to or */
12270       toBoolean (right);
12271       aopPut (result, "a", 0);
12272       goto release;
12273     }
12274
12275   /* bit variables done */
12276   /* general case */
12277   size = getDataSize (result);
12278   offset = 0;
12279   if (AOP_TYPE (right) == AOP_LIT)
12280     lit = ulFromVal (AOP (right)->aopu.aop_lit);
12281
12282   if ((size > 1) &&
12283       (AOP_TYPE (result) != AOP_REG) &&
12284       (AOP_TYPE (right) == AOP_LIT) &&
12285       !IS_FLOAT (operandType (right)))
12286     {
12287       _startLazyDPSEvaluation ();
12288       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12289         {
12290           aopPut (result,
12291                   aopGet (right, offset, FALSE, FALSE, NULL),
12292                   offset);
12293           offset++;
12294           size--;
12295         }
12296       /* And now fill the rest with zeros. */
12297       if (size)
12298         {
12299           emitcode ("clr", "a");
12300         }
12301       while (size--)
12302         {
12303           aopPut (result, "a", offset++);
12304         }
12305       _endLazyDPSEvaluation ();
12306     }
12307   else
12308     {
12309       _startLazyDPSEvaluation ();
12310       while (size--)
12311         {
12312           aopPut (result,
12313                   aopGet (right, offset, FALSE, FALSE, NULL),
12314                   offset);
12315           offset++;
12316         }
12317       _endLazyDPSEvaluation ();
12318     }
12319   adjustArithmeticResult (ic);
12320
12321 release:
12322   freeAsmop (result, NULL, ic, TRUE);
12323   freeAsmop (right, NULL, ic, TRUE);
12324 }
12325
12326 /*-----------------------------------------------------------------*/
12327 /* genJumpTab - generates code for jump table                      */
12328 /*-----------------------------------------------------------------*/
12329 static void
12330 genJumpTab (iCode * ic)
12331 {
12332   symbol *jtab;
12333   char *l;
12334
12335   D (emitcode (";", "genJumpTab"));
12336
12337   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12338   /* get the condition into accumulator */
12339   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12340   MOVA (l);
12341   /* multiply by four! */
12342   emitcode ("add", "a,acc");
12343   emitcode ("add", "a,acc");
12344   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12345
12346   jtab = newiTempLabel (NULL);
12347   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12348   emitcode ("jmp", "@a+dptr");
12349   emitLabel (jtab);
12350   /* now generate the jump labels */
12351   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12352        jtab = setNextItem (IC_JTLABELS (ic)))
12353     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12354
12355 }
12356
12357 /*-----------------------------------------------------------------*/
12358 /* genCast - gen code for casting                                  */
12359 /*-----------------------------------------------------------------*/
12360 static void
12361 genCast (iCode * ic)
12362 {
12363   operand *result = IC_RESULT (ic);
12364   sym_link *ctype = operandType (IC_LEFT (ic));
12365   sym_link *rtype = operandType (IC_RIGHT (ic));
12366   operand *right = IC_RIGHT (ic);
12367   int size, offset;
12368
12369   D (emitcode (";", "genCast"));
12370
12371   /* if they are equivalent then do nothing */
12372   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12373     return;
12374
12375   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12376   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12377
12378   /* if the result is a bit (and not a bitfield) */
12379   if (IS_BIT (OP_SYMBOL (result)->type))
12380     {
12381       /* if the right size is a literal then
12382          we know what the value is */
12383       if (AOP_TYPE (right) == AOP_LIT)
12384         {
12385           if (((int) operandLitValue (right)))
12386             aopPut (result, one, 0);
12387           else
12388             aopPut (result, zero, 0);
12389
12390           goto release;
12391         }
12392
12393       /* the right is also a bit variable */
12394       if (AOP_TYPE (right) == AOP_CRY)
12395         {
12396           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12397           aopPut (result, "c", 0);
12398           goto release;
12399         }
12400
12401       /* we need to or */
12402       toBoolean (right);
12403       aopPut (result, "a", 0);
12404       goto release;
12405     }
12406
12407   /* if they are the same size : or less */
12408   if (AOP_SIZE (result) <= AOP_SIZE (right))
12409     {
12410
12411       /* if they are in the same place */
12412       if (sameRegs (AOP (right), AOP (result)))
12413         goto release;
12414
12415       /* if they in different places then copy */
12416       size = AOP_SIZE (result);
12417       offset = 0;
12418       _startLazyDPSEvaluation ();
12419       while (size--)
12420         {
12421           aopPut (result,
12422                   aopGet (right, offset, FALSE, FALSE, NULL),
12423                   offset);
12424           offset++;
12425         }
12426       _endLazyDPSEvaluation ();
12427       goto release;
12428     }
12429
12430   /* if the result is of type pointer */
12431   if (IS_PTR (ctype))
12432     {
12433
12434       int p_type;
12435       sym_link *type = operandType (right);
12436
12437       /* pointer to generic pointer */
12438       if (IS_GENPTR (ctype))
12439         {
12440           if (IS_PTR (type))
12441             {
12442               p_type = DCL_TYPE (type);
12443             }
12444           else
12445             {
12446 #if OLD_CAST_BEHAVIOR
12447               /* KV: we are converting a non-pointer type to
12448                * a generic pointer. This (ifdef'd out) code
12449                * says that the resulting generic pointer
12450                * should have the same class as the storage
12451                * location of the non-pointer variable.
12452                *
12453                * For example, converting an int (which happens
12454                * to be stored in DATA space) to a pointer results
12455                * in a DATA generic pointer; if the original int
12456                * in XDATA space, so will be the resulting pointer.
12457                *
12458                * I don't like that behavior, and thus this change:
12459                * all such conversions will be forced to XDATA and
12460                * throw a warning. If you want some non-XDATA
12461                * type, or you want to suppress the warning, you
12462                * must go through an intermediate cast, like so:
12463                *
12464                * char _generic *gp = (char _xdata *)(intVar);
12465                */
12466               sym_link *etype = getSpec (type);
12467
12468               /* we have to go by the storage class */
12469               if (SPEC_OCLS (etype) != generic)
12470                 {
12471                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12472                 }
12473               else
12474 #endif
12475                 {
12476                   /* Converting unknown class (i.e. register variable)
12477                    * to generic pointer. This is not good, but
12478                    * we'll make a guess (and throw a warning).
12479                    */
12480                   p_type = FPOINTER;
12481                   werror (W_INT_TO_GEN_PTR_CAST);
12482                 }
12483             }
12484
12485           /* the first two bytes are known */
12486           size = GPTRSIZE - 1;
12487           offset = 0;
12488           _startLazyDPSEvaluation ();
12489           while (size--)
12490             {
12491               aopPut (result,
12492                       aopGet (right, offset, FALSE, FALSE, NULL),
12493                       offset);
12494               offset++;
12495             }
12496           _endLazyDPSEvaluation ();
12497
12498           /* the last byte depending on type */
12499             {
12500                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12501                 char gpValStr[10];
12502
12503                 if (gpVal == -1)
12504                 {
12505                     // pointerTypeToGPByte will have bitched.
12506                     exit(1);
12507                 }
12508
12509                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12510                 aopPut (result, gpValStr, GPTRSIZE - 1);
12511             }
12512           goto release;
12513         }
12514
12515       /* just copy the pointers */
12516       size = AOP_SIZE (result);
12517       offset = 0;
12518       _startLazyDPSEvaluation ();
12519       while (size--)
12520         {
12521           aopPut (result,
12522                   aopGet (right, offset, FALSE, FALSE, NULL),
12523                   offset);
12524           offset++;
12525         }
12526       _endLazyDPSEvaluation ();
12527       goto release;
12528     }
12529
12530   /* so we now know that the size of destination is greater
12531      than the size of the source */
12532   /* we move to result for the size of source */
12533   size = AOP_SIZE (right);
12534   offset = 0;
12535   _startLazyDPSEvaluation ();
12536   while (size--)
12537     {
12538       aopPut (result,
12539               aopGet (right, offset, FALSE, FALSE, NULL),
12540               offset);
12541       offset++;
12542     }
12543   _endLazyDPSEvaluation ();
12544
12545   /* now depending on the sign of the source && destination */
12546   size = AOP_SIZE (result) - AOP_SIZE (right);
12547   /* if unsigned or not an integral type */
12548   /* also, if the source is a bit, we don't need to sign extend, because
12549    * it can't possibly have set the sign bit.
12550    */
12551   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12552     {
12553       while (size--)
12554         {
12555           aopPut (result, zero, offset++);
12556         }
12557     }
12558   else
12559     {
12560       /* we need to extend the sign :{ */
12561       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12562                         FALSE, FALSE, NULL));
12563       emitcode ("rlc", "a");
12564       emitcode ("subb", "a,acc");
12565       while (size--)
12566         aopPut (result, "a", offset++);
12567     }
12568
12569   /* we are done hurray !!!! */
12570
12571 release:
12572   freeAsmop (right, NULL, ic, TRUE);
12573   freeAsmop (result, NULL, ic, TRUE);
12574
12575 }
12576
12577 /*-----------------------------------------------------------------*/
12578 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12579 /*-----------------------------------------------------------------*/
12580 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12581 {
12582     operand *from , *to , *count;
12583     symbol *lbl;
12584     bitVect *rsave;
12585     int i;
12586
12587     /* we know it has to be 3 parameters */
12588     assert (nparms == 3);
12589
12590     rsave = newBitVect(16);
12591     /* save DPTR if it needs to be saved */
12592     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12593             if (bitVectBitValue(ic->rMask,i))
12594                     rsave = bitVectSetBit(rsave,i);
12595     }
12596     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12597                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12598     savermask(rsave);
12599
12600     to = parms[0];
12601     from = parms[1];
12602     count = parms[2];
12603
12604     aopOp (from, ic->next, FALSE, FALSE);
12605
12606     /* get from into DPTR1 */
12607     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12608     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12609     if (options.model == MODEL_FLAT24) {
12610         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12611     }
12612
12613     freeAsmop (from, NULL, ic, FALSE);
12614     aopOp (to, ic, FALSE, FALSE);
12615     /* get "to" into DPTR */
12616     /* if the operand is already in dptr
12617        then we do nothing else we move the value to dptr */
12618     if (AOP_TYPE (to) != AOP_STR) {
12619         /* if already in DPTR then we need to push */
12620         if (AOP_TYPE(to) == AOP_DPTR) {
12621             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12622             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12623             if (options.model == MODEL_FLAT24)
12624                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12625             emitcode ("pop", "dph");
12626             emitcode ("pop", "dpl");
12627         } else {
12628             _startLazyDPSEvaluation ();
12629             /* if this is remateriazable */
12630             if (AOP_TYPE (to) == AOP_IMMD) {
12631                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12632             } else {                    /* we need to get it byte by byte */
12633                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12634                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12635                 if (options.model == MODEL_FLAT24) {
12636                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12637                 }
12638             }
12639             _endLazyDPSEvaluation ();
12640         }
12641     }
12642     freeAsmop (to, NULL, ic, FALSE);
12643     _G.dptrInUse = _G.dptr1InUse = 1;
12644     aopOp (count, ic->next->next, FALSE,FALSE);
12645     lbl =newiTempLabel(NULL);
12646
12647     /* now for the actual copy */
12648     if (AOP_TYPE(count) == AOP_LIT &&
12649         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12650         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12651         if (fromc) {
12652             emitcode ("lcall","__bi_memcpyc2x_s");
12653         } else {
12654             emitcode ("lcall","__bi_memcpyx2x_s");
12655         }
12656         freeAsmop (count, NULL, ic, FALSE);
12657     } else {
12658         symbol *lbl1 = newiTempLabel(NULL);
12659
12660         emitcode (";"," Auto increment but no djnz");
12661         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12662         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12663         freeAsmop (count, NULL, ic, FALSE);
12664         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12665         emitLabel (lbl);
12666         if (fromc) {
12667             emitcode ("clr","a");
12668             emitcode ("movc", "a,@a+dptr");
12669         } else
12670             emitcode ("movx", "a,@dptr");
12671         emitcode ("movx", "@dptr,a");
12672         emitcode ("inc", "dptr");
12673         emitcode ("inc", "dptr");
12674         emitcode ("mov","a,b");
12675         emitcode ("orl","a,_ap");
12676         emitcode ("jz","!tlabel",lbl1->key+100);
12677         emitcode ("mov","a,_ap");
12678         emitcode ("add","a,#!constbyte",0xFF);
12679         emitcode ("mov","_ap,a");
12680         emitcode ("mov","a,b");
12681         emitcode ("addc","a,#!constbyte",0xFF);
12682         emitcode ("mov","b,a");
12683         emitcode ("sjmp","!tlabel",lbl->key+100);
12684         emitLabel (lbl1);
12685     }
12686     emitcode ("mov", "dps,#0");
12687     _G.dptrInUse = _G.dptr1InUse = 0;
12688     unsavermask(rsave);
12689
12690 }
12691
12692 /*-----------------------------------------------------------------*/
12693 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12694 /*-----------------------------------------------------------------*/
12695 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12696 {
12697     operand *from , *to , *count;
12698     symbol *lbl,*lbl2;
12699     bitVect *rsave;
12700     int i;
12701
12702     /* we know it has to be 3 parameters */
12703     assert (nparms == 3);
12704
12705     rsave = newBitVect(16);
12706     /* save DPTR if it needs to be saved */
12707     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12708             if (bitVectBitValue(ic->rMask,i))
12709                     rsave = bitVectSetBit(rsave,i);
12710     }
12711     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12712                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12713     savermask(rsave);
12714
12715     to = parms[0];
12716     from = parms[1];
12717     count = parms[2];
12718
12719     aopOp (from, ic->next, FALSE, FALSE);
12720
12721     /* get from into DPTR1 */
12722     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12723     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12724     if (options.model == MODEL_FLAT24) {
12725         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12726     }
12727
12728     freeAsmop (from, NULL, ic, FALSE);
12729     aopOp (to, ic, FALSE, FALSE);
12730     /* get "to" into DPTR */
12731     /* if the operand is already in dptr
12732        then we do nothing else we move the value to dptr */
12733     if (AOP_TYPE (to) != AOP_STR) {
12734         /* if already in DPTR then we need to push */
12735         if (AOP_TYPE(to) == AOP_DPTR) {
12736             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12737             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12738             if (options.model == MODEL_FLAT24)
12739                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12740             emitcode ("pop", "dph");
12741             emitcode ("pop", "dpl");
12742         } else {
12743             _startLazyDPSEvaluation ();
12744             /* if this is remateriazable */
12745             if (AOP_TYPE (to) == AOP_IMMD) {
12746                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12747             } else {                    /* we need to get it byte by byte */
12748                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12749                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12750                 if (options.model == MODEL_FLAT24) {
12751                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12752                 }
12753             }
12754             _endLazyDPSEvaluation ();
12755         }
12756     }
12757     freeAsmop (to, NULL, ic, FALSE);
12758     _G.dptrInUse = _G.dptr1InUse = 1;
12759     aopOp (count, ic->next->next, FALSE,FALSE);
12760     lbl =newiTempLabel(NULL);
12761     lbl2 =newiTempLabel(NULL);
12762
12763     /* now for the actual compare */
12764     if (AOP_TYPE(count) == AOP_LIT &&
12765         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12766         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12767         if (fromc)
12768             emitcode("lcall","__bi_memcmpc2x_s");
12769         else
12770             emitcode("lcall","__bi_memcmpx2x_s");
12771         freeAsmop (count, NULL, ic, FALSE);
12772         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12773         aopPut(IC_RESULT(ic),"a",0);
12774         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12775     } else {
12776         symbol *lbl1 = newiTempLabel(NULL);
12777
12778         emitcode("push","ar0");
12779         emitcode (";"," Auto increment but no djnz");
12780         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12781         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12782         freeAsmop (count, NULL, ic, FALSE);
12783         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12784         emitLabel (lbl);
12785         if (fromc) {
12786             emitcode ("clr","a");
12787             emitcode ("movc", "a,@a+dptr");
12788         } else
12789             emitcode ("movx", "a,@dptr");
12790         emitcode ("mov","r0,a");
12791         emitcode ("movx", "a,@dptr");
12792         emitcode ("clr","c");
12793         emitcode ("subb","a,r0");
12794         emitcode ("jnz","!tlabel",lbl2->key+100);
12795         emitcode ("inc", "dptr");
12796         emitcode ("inc", "dptr");
12797         emitcode ("mov","a,b");
12798         emitcode ("orl","a,_ap");
12799         emitcode ("jz","!tlabel",lbl1->key+100);
12800         emitcode ("mov","a,_ap");
12801         emitcode ("add","a,#!constbyte",0xFF);
12802         emitcode ("mov","_ap,a");
12803         emitcode ("mov","a,b");
12804         emitcode ("addc","a,#!constbyte",0xFF);
12805         emitcode ("mov","b,a");
12806         emitcode ("sjmp","!tlabel",lbl->key+100);
12807         emitLabel (lbl1);
12808         emitcode ("clr","a");
12809         emitLabel (lbl2);
12810         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12811         aopPut(IC_RESULT(ic),"a",0);
12812         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12813         emitcode("pop","ar0");
12814         emitcode ("mov", "dps,#0");
12815     }
12816     _G.dptrInUse = _G.dptr1InUse = 0;
12817     unsavermask(rsave);
12818
12819 }
12820
12821 /*-----------------------------------------------------------------*/
12822 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12823 /* port, first parameter output area second parameter pointer to   */
12824 /* port third parameter count                                      */
12825 /*-----------------------------------------------------------------*/
12826 static void genInp( iCode *ic, int nparms, operand **parms)
12827 {
12828     operand *from , *to , *count;
12829     symbol *lbl;
12830     bitVect *rsave;
12831     int i;
12832
12833     /* we know it has to be 3 parameters */
12834     assert (nparms == 3);
12835
12836     rsave = newBitVect(16);
12837     /* save DPTR if it needs to be saved */
12838     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12839             if (bitVectBitValue(ic->rMask,i))
12840                     rsave = bitVectSetBit(rsave,i);
12841     }
12842     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12843                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12844     savermask(rsave);
12845
12846     to = parms[0];
12847     from = parms[1];
12848     count = parms[2];
12849
12850     aopOp (from, ic->next, FALSE, FALSE);
12851
12852     /* get from into DPTR1 */
12853     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12854     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12855     if (options.model == MODEL_FLAT24) {
12856         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12857     }
12858
12859     freeAsmop (from, NULL, ic, FALSE);
12860     aopOp (to, ic, FALSE, FALSE);
12861     /* get "to" into DPTR */
12862     /* if the operand is already in dptr
12863        then we do nothing else we move the value to dptr */
12864     if (AOP_TYPE (to) != AOP_STR) {
12865         /* if already in DPTR then we need to push */
12866         if (AOP_TYPE(to) == AOP_DPTR) {
12867             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12868             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12869             if (options.model == MODEL_FLAT24)
12870                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12871             emitcode ("pop", "dph");
12872             emitcode ("pop", "dpl");
12873         } else {
12874             _startLazyDPSEvaluation ();
12875             /* if this is remateriazable */
12876             if (AOP_TYPE (to) == AOP_IMMD) {
12877                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12878             } else {                    /* we need to get it byte by byte */
12879                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12880                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12881                 if (options.model == MODEL_FLAT24) {
12882                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12883                 }
12884             }
12885             _endLazyDPSEvaluation ();
12886         }
12887     }
12888     freeAsmop (to, NULL, ic, FALSE);
12889
12890     _G.dptrInUse = _G.dptr1InUse = 1;
12891     aopOp (count, ic->next->next, FALSE,FALSE);
12892     lbl =newiTempLabel(NULL);
12893
12894     /* now for the actual copy */
12895     if (AOP_TYPE(count) == AOP_LIT &&
12896         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12897         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12898         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12899         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12900         freeAsmop (count, NULL, ic, FALSE);
12901         emitLabel (lbl);
12902         emitcode ("movx", "a,@dptr");   /* read data from port */
12903         emitcode ("dec","dps");         /* switch to DPTR */
12904         emitcode ("movx", "@dptr,a");   /* save into location */
12905         emitcode ("inc", "dptr");       /* point to next area */
12906         emitcode ("inc","dps");         /* switch to DPTR2 */
12907         emitcode ("djnz","b,!tlabel",lbl->key+100);
12908     } else {
12909         symbol *lbl1 = newiTempLabel(NULL);
12910
12911         emitcode (";"," Auto increment but no djnz");
12912         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12913         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12914         freeAsmop (count, NULL, ic, FALSE);
12915         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12916         emitLabel (lbl);
12917         emitcode ("movx", "a,@dptr");
12918         emitcode ("dec","dps");         /* switch to DPTR */
12919         emitcode ("movx", "@dptr,a");
12920         emitcode ("inc", "dptr");
12921         emitcode ("inc","dps");         /* switch to DPTR2 */
12922 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12923 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12924         emitcode ("mov","a,b");
12925         emitcode ("orl","a,_ap");
12926         emitcode ("jz","!tlabel",lbl1->key+100);
12927         emitcode ("mov","a,_ap");
12928         emitcode ("add","a,#!constbyte",0xFF);
12929         emitcode ("mov","_ap,a");
12930         emitcode ("mov","a,b");
12931         emitcode ("addc","a,#!constbyte",0xFF);
12932         emitcode ("mov","b,a");
12933         emitcode ("sjmp","!tlabel",lbl->key+100);
12934         emitLabel (lbl1);
12935     }
12936     emitcode ("mov", "dps,#0");
12937     _G.dptrInUse = _G.dptr1InUse = 0;
12938     unsavermask(rsave);
12939
12940 }
12941
12942 /*-----------------------------------------------------------------*/
12943 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12944 /* port, first parameter output area second parameter pointer to   */
12945 /* port third parameter count                                      */
12946 /*-----------------------------------------------------------------*/
12947 static void genOutp( iCode *ic, int nparms, operand **parms)
12948 {
12949     operand *from , *to , *count;
12950     symbol *lbl;
12951     bitVect *rsave;
12952     int i;
12953
12954     /* we know it has to be 3 parameters */
12955     assert (nparms == 3);
12956
12957     rsave = newBitVect(16);
12958     /* save DPTR if it needs to be saved */
12959     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12960             if (bitVectBitValue(ic->rMask,i))
12961                     rsave = bitVectSetBit(rsave,i);
12962     }
12963     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12964                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12965     savermask(rsave);
12966
12967     to = parms[0];
12968     from = parms[1];
12969     count = parms[2];
12970
12971     aopOp (from, ic->next, FALSE, FALSE);
12972
12973     /* get from into DPTR1 */
12974     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12975     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12976     if (options.model == MODEL_FLAT24) {
12977         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12978     }
12979
12980     freeAsmop (from, NULL, ic, FALSE);
12981     aopOp (to, ic, FALSE, FALSE);
12982     /* get "to" into DPTR */
12983     /* if the operand is already in dptr
12984        then we do nothing else we move the value to dptr */
12985     if (AOP_TYPE (to) != AOP_STR) {
12986         /* if already in DPTR then we need to push */
12987         if (AOP_TYPE(to) == AOP_DPTR) {
12988             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12989             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12990             if (options.model == MODEL_FLAT24)
12991                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12992             emitcode ("pop", "dph");
12993             emitcode ("pop", "dpl");
12994         } else {
12995             _startLazyDPSEvaluation ();
12996             /* if this is remateriazable */
12997             if (AOP_TYPE (to) == AOP_IMMD) {
12998                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12999             } else {                    /* we need to get it byte by byte */
13000                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13001                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13002                 if (options.model == MODEL_FLAT24) {
13003                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13004                 }
13005             }
13006             _endLazyDPSEvaluation ();
13007         }
13008     }
13009     freeAsmop (to, NULL, ic, FALSE);
13010
13011     _G.dptrInUse = _G.dptr1InUse = 1;
13012     aopOp (count, ic->next->next, FALSE,FALSE);
13013     lbl =newiTempLabel(NULL);
13014
13015     /* now for the actual copy */
13016     if (AOP_TYPE(count) == AOP_LIT &&
13017         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13018         emitcode (";","OH  JOY auto increment with djnz (very fast)");
13019         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13020         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13021         emitLabel (lbl);
13022         emitcode ("movx", "a,@dptr");   /* read data from port */
13023         emitcode ("inc","dps");         /* switch to DPTR2 */
13024         emitcode ("movx", "@dptr,a");   /* save into location */
13025         emitcode ("inc", "dptr");       /* point to next area */
13026         emitcode ("dec","dps");         /* switch to DPTR */
13027         emitcode ("djnz","b,!tlabel",lbl->key+100);
13028         freeAsmop (count, NULL, ic, FALSE);
13029     } else {
13030         symbol *lbl1 = newiTempLabel(NULL);
13031
13032         emitcode (";"," Auto increment but no djnz");
13033         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13034         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13035         freeAsmop (count, NULL, ic, FALSE);
13036         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13037         emitLabel (lbl);
13038         emitcode ("movx", "a,@dptr");
13039         emitcode ("inc", "dptr");
13040         emitcode ("inc","dps");         /* switch to DPTR2 */
13041         emitcode ("movx", "@dptr,a");
13042         emitcode ("dec","dps");         /* switch to DPTR */
13043         emitcode ("mov","a,b");
13044         emitcode ("orl","a,_ap");
13045         emitcode ("jz","!tlabel",lbl1->key+100);
13046         emitcode ("mov","a,_ap");
13047         emitcode ("add","a,#!constbyte",0xFF);
13048         emitcode ("mov","_ap,a");
13049         emitcode ("mov","a,b");
13050         emitcode ("addc","a,#!constbyte",0xFF);
13051         emitcode ("mov","b,a");
13052         emitcode ("sjmp","!tlabel",lbl->key+100);
13053         emitLabel (lbl1);
13054     }
13055     emitcode ("mov", "dps,#0");
13056     _G.dptrInUse = _G.dptr1InUse = 0;
13057     unsavermask(rsave);
13058
13059 }
13060
13061 /*-----------------------------------------------------------------*/
13062 /* genSwapW - swap lower & high order bytes                        */
13063 /*-----------------------------------------------------------------*/
13064 static void genSwapW(iCode *ic, int nparms, operand **parms)
13065 {
13066     operand *dest;
13067     operand *src;
13068     assert (nparms==1);
13069
13070     src = parms[0];
13071     dest=IC_RESULT(ic);
13072
13073     assert(getSize(operandType(src))==2);
13074
13075     aopOp (src, ic, FALSE, FALSE);
13076     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13077     _G.accInUse++;
13078     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13079     _G.accInUse--;
13080     freeAsmop (src, NULL, ic, FALSE);
13081
13082     aopOp (dest,ic, FALSE, FALSE);
13083     aopPut(dest,"b",0);
13084     aopPut(dest,"a",1);
13085     freeAsmop (dest, NULL, ic, FALSE);
13086 }
13087
13088 /*-----------------------------------------------------------------*/
13089 /* genMemsetX - gencode for memSetX data                           */
13090 /*-----------------------------------------------------------------*/
13091 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13092 {
13093     operand *to , *val , *count;
13094     symbol *lbl;
13095     char *l;
13096     int i;
13097     bitVect *rsave;
13098
13099     /* we know it has to be 3 parameters */
13100     assert (nparms == 3);
13101
13102     to = parms[0];
13103     val = parms[1];
13104     count = parms[2];
13105
13106     /* save DPTR if it needs to be saved */
13107     rsave = newBitVect(16);
13108     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13109             if (bitVectBitValue(ic->rMask,i))
13110                     rsave = bitVectSetBit(rsave,i);
13111     }
13112     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13113                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13114     savermask(rsave);
13115
13116     aopOp (to, ic, FALSE, FALSE);
13117     /* get "to" into DPTR */
13118     /* if the operand is already in dptr
13119        then we do nothing else we move the value to dptr */
13120     if (AOP_TYPE (to) != AOP_STR) {
13121         /* if already in DPTR then we need to push */
13122         if (AOP_TYPE(to) == AOP_DPTR) {
13123             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13124             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13125             if (options.model == MODEL_FLAT24)
13126                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13127             emitcode ("pop", "dph");
13128             emitcode ("pop", "dpl");
13129         } else {
13130             _startLazyDPSEvaluation ();
13131             /* if this is remateriazable */
13132             if (AOP_TYPE (to) == AOP_IMMD) {
13133                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13134             } else {                    /* we need to get it byte by byte */
13135                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13136                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13137                 if (options.model == MODEL_FLAT24) {
13138                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13139                 }
13140             }
13141             _endLazyDPSEvaluation ();
13142         }
13143     }
13144     freeAsmop (to, NULL, ic, FALSE);
13145
13146     aopOp (val, ic->next->next, FALSE,FALSE);
13147     aopOp (count, ic->next->next, FALSE,FALSE);
13148     lbl =newiTempLabel(NULL);
13149     /* now for the actual copy */
13150     if (AOP_TYPE(count) == AOP_LIT &&
13151         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13152         l = aopGet(val, 0, FALSE, FALSE, NULL);
13153         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13154         MOVA(l);
13155         emitLabel (lbl);
13156         emitcode ("movx", "@dptr,a");
13157         emitcode ("inc", "dptr");
13158         emitcode ("djnz","b,!tlabel",lbl->key+100);
13159     } else {
13160         symbol *lbl1 = newiTempLabel(NULL);
13161
13162         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13163         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13164         emitLabel (lbl);
13165         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13166         emitcode ("movx", "@dptr,a");
13167         emitcode ("inc", "dptr");
13168         emitcode ("mov","a,b");
13169         emitcode ("orl","a,_ap");
13170         emitcode ("jz","!tlabel",lbl1->key+100);
13171         emitcode ("mov","a,_ap");
13172         emitcode ("add","a,#!constbyte",0xFF);
13173         emitcode ("mov","_ap,a");
13174         emitcode ("mov","a,b");
13175         emitcode ("addc","a,#!constbyte",0xFF);
13176         emitcode ("mov","b,a");
13177         emitcode ("sjmp","!tlabel",lbl->key+100);
13178         emitLabel (lbl1);
13179     }
13180     freeAsmop (count, NULL, ic, FALSE);
13181     unsavermask(rsave);
13182 }
13183
13184 /*-----------------------------------------------------------------*/
13185 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13186 /*-----------------------------------------------------------------*/
13187 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13188 {
13189         bitVect *rsave ;
13190         operand *pnum, *result;
13191         int i;
13192
13193         assert (nparms==1);
13194         /* save registers that need to be saved */
13195         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13196                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13197
13198         pnum = parms[0];
13199         aopOp (pnum, ic, FALSE, FALSE);
13200         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13201         freeAsmop (pnum, NULL, ic, FALSE);
13202         emitcode ("lcall","NatLib_LoadPrimitive");
13203         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13204         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13205             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13206                 for (i = (size-1) ; i >= 0 ; i-- ) {
13207                         emitcode ("push","a%s",javaRet[i]);
13208                 }
13209                 for (i=0; i < size ; i++ ) {
13210                         emitcode ("pop","a%s",
13211                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13212                 }
13213         } else {
13214                 for (i = 0 ; i < size ; i++ ) {
13215                         aopPut(result,javaRet[i],i);
13216                 }
13217         }
13218         freeAsmop (result, NULL, ic, FALSE);
13219         unsavermask(rsave);
13220 }
13221
13222 /*-----------------------------------------------------------------*/
13223 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13224 /*-----------------------------------------------------------------*/
13225 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13226 {
13227         bitVect *rsave ;
13228         operand *pnum, *result;
13229         int size = 3;
13230         int i;
13231
13232         assert (nparms==1);
13233         /* save registers that need to be saved */
13234         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13235                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13236
13237         pnum = parms[0];
13238         aopOp (pnum, ic, FALSE, FALSE);
13239         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13240         freeAsmop (pnum, NULL, ic, FALSE);
13241         emitcode ("lcall","NatLib_LoadPointer");
13242         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13243         if (AOP_TYPE(result)!=AOP_STR) {
13244                 for (i = 0 ; i < size ; i++ ) {
13245                         aopPut(result,fReturn[i],i);
13246                 }
13247         }
13248         freeAsmop (result, NULL, ic, FALSE);
13249         unsavermask(rsave);
13250 }
13251
13252 /*-----------------------------------------------------------------*/
13253 /* genNatLibInstallStateBlock -                                    */
13254 /*-----------------------------------------------------------------*/
13255 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13256                                        operand **parms, const char *name)
13257 {
13258         bitVect *rsave ;
13259         operand *psb, *handle;
13260         assert (nparms==2);
13261
13262         /* save registers that need to be saved */
13263         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13264                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13265         psb = parms[0];
13266         handle = parms[1];
13267
13268         /* put pointer to state block into DPTR1 */
13269         aopOp (psb, ic, FALSE, FALSE);
13270         if (AOP_TYPE (psb) == AOP_IMMD) {
13271                 emitcode ("mov","dps,#1");
13272                 emitcode ("mov", "dptr,%s",
13273                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13274                 emitcode ("mov","dps,#0");
13275         } else {
13276                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13277                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13278                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13279         }
13280         freeAsmop (psb, NULL, ic, FALSE);
13281
13282         /* put libraryID into DPTR */
13283         emitcode ("mov","dptr,#LibraryID");
13284
13285         /* put handle into r3:r2 */
13286         aopOp (handle, ic, FALSE, FALSE);
13287         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13288                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13289                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13290                 emitcode ("pop","ar3");
13291                 emitcode ("pop","ar2");
13292         } else {
13293                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13294                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13295         }
13296         freeAsmop (psb, NULL, ic, FALSE);
13297
13298         /* make the call */
13299         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13300
13301         /* put return value into place*/
13302         _G.accInUse++;
13303         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13304         _G.accInUse--;
13305         aopPut(IC_RESULT(ic),"a",0);
13306         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13307         unsavermask(rsave);
13308 }
13309
13310 /*-----------------------------------------------------------------*/
13311 /* genNatLibRemoveStateBlock -                                     */
13312 /*-----------------------------------------------------------------*/
13313 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13314 {
13315         bitVect *rsave ;
13316
13317         assert(nparms==0);
13318
13319         /* save registers that need to be saved */
13320         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13321                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13322
13323         /* put libraryID into DPTR */
13324         emitcode ("mov","dptr,#LibraryID");
13325         /* make the call */
13326         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13327         unsavermask(rsave);
13328 }
13329
13330 /*-----------------------------------------------------------------*/
13331 /* genNatLibGetStateBlock -                                        */
13332 /*-----------------------------------------------------------------*/
13333 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13334                                    operand **parms,const char *name)
13335 {
13336         bitVect *rsave ;
13337         symbol *lbl = newiTempLabel(NULL);
13338
13339         assert(nparms==0);
13340         /* save registers that need to be saved */
13341         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13342                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13343
13344         /* put libraryID into DPTR */
13345         emitcode ("mov","dptr,#LibraryID");
13346         /* make the call */
13347         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13348         emitcode ("jnz","!tlabel",lbl->key+100);
13349
13350         /* put return value into place */
13351         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13352         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13353                 emitcode ("push","ar3");
13354                 emitcode ("push","ar2");
13355                 emitcode ("pop","%s",
13356                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13357                 emitcode ("pop","%s",
13358                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13359         } else {
13360                 aopPut(IC_RESULT(ic),"r2",0);
13361                 aopPut(IC_RESULT(ic),"r3",1);
13362         }
13363         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13364         emitLabel (lbl);
13365         unsavermask(rsave);
13366 }
13367
13368 /*-----------------------------------------------------------------*/
13369 /* genMMMalloc -                                                   */
13370 /*-----------------------------------------------------------------*/
13371 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13372                          int size, const char *name)
13373 {
13374         bitVect *rsave ;
13375         operand *bsize;
13376         symbol *rsym;
13377         symbol *lbl = newiTempLabel(NULL);
13378
13379         assert (nparms == 1);
13380         /* save registers that need to be saved */
13381         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13382                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13383
13384         bsize=parms[0];
13385         aopOp (bsize,ic,FALSE,FALSE);
13386
13387         /* put the size in R4-R2 */
13388         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13389                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13390                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13391                 if (size==3) {
13392                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13393                         emitcode("pop","ar4");
13394                 }
13395                 emitcode("pop","ar3");
13396                 emitcode("pop","ar2");
13397         } else {
13398                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13399                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13400                 if (size==3) {
13401                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13402                 }
13403         }
13404         freeAsmop (bsize, NULL, ic, FALSE);
13405
13406         /* make the call */
13407         emitcode ("lcall","MM_%s",name);
13408         emitcode ("jz","!tlabel",lbl->key+100);
13409         emitcode ("mov","r2,#!constbyte",0xff);
13410         emitcode ("mov","r3,#!constbyte",0xff);
13411         emitLabel (lbl);
13412         /* we don't care about the pointer : we just save the handle */
13413         rsym = OP_SYMBOL(IC_RESULT(ic));
13414         if (rsym->liveFrom != rsym->liveTo) {
13415                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13416                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13417                         emitcode ("push","ar3");
13418                         emitcode ("push","ar2");
13419                         emitcode ("pop","%s",
13420                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13421                         emitcode ("pop","%s",
13422                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13423                 } else {
13424                         aopPut(IC_RESULT(ic),"r2",0);
13425                         aopPut(IC_RESULT(ic),"r3",1);
13426                 }
13427                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13428         }
13429         unsavermask(rsave);
13430 }
13431
13432 /*-----------------------------------------------------------------*/
13433 /* genMMDeref -                                                    */
13434 /*-----------------------------------------------------------------*/
13435 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13436 {
13437         bitVect *rsave ;
13438         operand *handle;
13439
13440         assert (nparms == 1);
13441         /* save registers that need to be saved */
13442         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13443                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13444
13445         handle=parms[0];
13446         aopOp (handle,ic,FALSE,FALSE);
13447
13448         /* put the size in R4-R2 */
13449         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13450                 emitcode("push","%s",
13451                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13452                 emitcode("push","%s",
13453                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13454                 emitcode("pop","ar3");
13455                 emitcode("pop","ar2");
13456         } else {
13457                 emitcode ("mov","r2,%s",
13458                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13459                 emitcode ("mov","r3,%s",
13460                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13461         }
13462         freeAsmop (handle, NULL, ic, FALSE);
13463
13464         /* make the call */
13465         emitcode ("lcall","MM_Deref");
13466
13467         {
13468                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13469                 if (rsym->liveFrom != rsym->liveTo) {
13470                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13471                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13472                             _startLazyDPSEvaluation ();
13473
13474                             aopPut(IC_RESULT(ic),"dpl",0);
13475                             aopPut(IC_RESULT(ic),"dph",1);
13476                             aopPut(IC_RESULT(ic),"dpx",2);
13477
13478                             _endLazyDPSEvaluation ();
13479
13480                         }
13481                 }
13482         }
13483         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13484         unsavermask(rsave);
13485 }
13486
13487 /*-----------------------------------------------------------------*/
13488 /* genMMUnrestrictedPersist -                                      */
13489 /*-----------------------------------------------------------------*/
13490 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13491 {
13492         bitVect *rsave ;
13493         operand *handle;
13494
13495         assert (nparms == 1);
13496         /* save registers that need to be saved */
13497         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13498                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13499
13500         handle=parms[0];
13501         aopOp (handle,ic,FALSE,FALSE);
13502
13503         /* put the size in R3-R2 */
13504         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13505                 emitcode("push","%s",
13506                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13507                 emitcode("push","%s",
13508                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13509                 emitcode("pop","ar3");
13510                 emitcode("pop","ar2");
13511         } else {
13512                 emitcode ("mov","r2,%s",
13513                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13514                 emitcode ("mov","r3,%s",
13515                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13516         }
13517         freeAsmop (handle, NULL, ic, FALSE);
13518
13519         /* make the call */
13520         emitcode ("lcall","MM_UnrestrictedPersist");
13521
13522         {
13523                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13524                 if (rsym->liveFrom != rsym->liveTo) {
13525                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13526                         aopPut(IC_RESULT(ic),"a",0);
13527                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13528                 }
13529         }
13530         unsavermask(rsave);
13531 }
13532
13533 /*-----------------------------------------------------------------*/
13534 /* genSystemExecJavaProcess -                                      */
13535 /*-----------------------------------------------------------------*/
13536 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13537 {
13538         bitVect *rsave ;
13539         operand *handle, *pp;
13540
13541         assert (nparms==2);
13542         /* save registers that need to be saved */
13543         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13544                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13545
13546         pp = parms[0];
13547         handle = parms[1];
13548
13549         /* put the handle in R3-R2 */
13550         aopOp (handle,ic,FALSE,FALSE);
13551         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13552                 emitcode("push","%s",
13553                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13554                 emitcode("push","%s",
13555                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13556                 emitcode("pop","ar3");
13557                 emitcode("pop","ar2");
13558         } else {
13559                 emitcode ("mov","r2,%s",
13560                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13561                 emitcode ("mov","r3,%s",
13562                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13563         }
13564         freeAsmop (handle, NULL, ic, FALSE);
13565
13566         /* put pointer in DPTR */
13567         aopOp (pp,ic,FALSE,FALSE);
13568         if (AOP_TYPE(pp) == AOP_IMMD) {
13569                 emitcode ("mov", "dptr,%s",
13570                           aopGet (pp, 0, TRUE, FALSE, NULL));
13571         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13572                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13573                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13574                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13575         }
13576         freeAsmop (handle, NULL, ic, FALSE);
13577
13578         /* make the call */
13579         emitcode ("lcall","System_ExecJavaProcess");
13580
13581         /* put result in place */
13582         {
13583                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13584                 if (rsym->liveFrom != rsym->liveTo) {
13585                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13586                         aopPut(IC_RESULT(ic),"a",0);
13587                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13588                 }
13589         }
13590
13591         unsavermask(rsave);
13592 }
13593
13594 /*-----------------------------------------------------------------*/
13595 /* genSystemRTCRegisters -                                         */
13596 /*-----------------------------------------------------------------*/
13597 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13598                                   char *name)
13599 {
13600         bitVect *rsave ;
13601         operand *pp;
13602
13603         assert (nparms==1);
13604         /* save registers that need to be saved */
13605         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13606                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13607
13608         pp=parms[0];
13609         /* put pointer in DPTR */
13610         aopOp (pp,ic,FALSE,FALSE);
13611         if (AOP_TYPE (pp) == AOP_IMMD) {
13612                 emitcode ("mov","dps,#1");
13613                 emitcode ("mov", "dptr,%s",
13614                           aopGet (pp, 0, TRUE, FALSE, NULL));
13615                 emitcode ("mov","dps,#0");
13616         } else {
13617                 emitcode ("mov","dpl1,%s",
13618                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13619                 emitcode ("mov","dph1,%s",
13620                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13621                 emitcode ("mov","dpx1,%s",
13622                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13623         }
13624         freeAsmop (pp, NULL, ic, FALSE);
13625
13626         /* make the call */
13627         emitcode ("lcall","System_%sRTCRegisters",name);
13628
13629         unsavermask(rsave);
13630 }
13631
13632 /*-----------------------------------------------------------------*/
13633 /* genSystemThreadSleep -                                          */
13634 /*-----------------------------------------------------------------*/
13635 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13636 {
13637         bitVect *rsave ;
13638         operand *to, *s;
13639
13640         assert (nparms==1);
13641         /* save registers that need to be saved */
13642         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13643                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13644
13645         to = parms[0];
13646         aopOp(to,ic,FALSE,FALSE);
13647         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13648             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13649                 emitcode ("push","%s",
13650                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13651                 emitcode ("push","%s",
13652                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13653                 emitcode ("push","%s",
13654                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13655                 emitcode ("push","%s",
13656                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13657                 emitcode ("pop","ar3");
13658                 emitcode ("pop","ar2");
13659                 emitcode ("pop","ar1");
13660                 emitcode ("pop","ar0");
13661         } else {
13662                 emitcode ("mov","r0,%s",
13663                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13664                 emitcode ("mov","r1,%s",
13665                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13666                 emitcode ("mov","r2,%s",
13667                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13668                 emitcode ("mov","r3,%s",
13669                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13670         }
13671         freeAsmop (to, NULL, ic, FALSE);
13672
13673         /* suspend in acc */
13674         s = parms[1];
13675         aopOp(s,ic,FALSE,FALSE);
13676         emitcode ("mov","a,%s",
13677                   aopGet(s,0,FALSE,TRUE,NULL));
13678         freeAsmop (s, NULL, ic, FALSE);
13679
13680         /* make the call */
13681         emitcode ("lcall","System_%s",name);
13682
13683         unsavermask(rsave);
13684 }
13685
13686 /*-----------------------------------------------------------------*/
13687 /* genSystemThreadResume -                                         */
13688 /*-----------------------------------------------------------------*/
13689 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13690 {
13691         bitVect *rsave ;
13692         operand *tid,*pid;
13693
13694         assert (nparms==2);
13695         /* save registers that need to be saved */
13696         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13697                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13698
13699         tid = parms[0];
13700         pid = parms[1];
13701
13702         /* PID in R0 */
13703         aopOp(pid,ic,FALSE,FALSE);
13704         emitcode ("mov","r0,%s",
13705                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13706         freeAsmop (pid, NULL, ic, FALSE);
13707
13708         /* tid into ACC */
13709         aopOp(tid,ic,FALSE,FALSE);
13710         emitcode ("mov","a,%s",
13711                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13712         freeAsmop (tid, NULL, ic, FALSE);
13713
13714         emitcode ("lcall","System_ThreadResume");
13715
13716         /* put result into place */
13717         {
13718                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13719                 if (rsym->liveFrom != rsym->liveTo) {
13720                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13721                         aopPut(IC_RESULT(ic),"a",0);
13722                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13723                 }
13724         }
13725         unsavermask(rsave);
13726 }
13727
13728 /*-----------------------------------------------------------------*/
13729 /* genSystemProcessResume -                                        */
13730 /*-----------------------------------------------------------------*/
13731 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13732 {
13733         bitVect *rsave ;
13734         operand *pid;
13735
13736         assert (nparms==1);
13737         /* save registers that need to be saved */
13738         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13739                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13740
13741         pid = parms[0];
13742
13743         /* pid into ACC */
13744         aopOp(pid,ic,FALSE,FALSE);
13745         emitcode ("mov","a,%s",
13746                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13747         freeAsmop (pid, NULL, ic, FALSE);
13748
13749         emitcode ("lcall","System_ProcessResume");
13750
13751         unsavermask(rsave);
13752 }
13753
13754 /*-----------------------------------------------------------------*/
13755 /* genSystem -                                                     */
13756 /*-----------------------------------------------------------------*/
13757 static void genSystem (iCode *ic,int nparms,char *name)
13758 {
13759         assert(nparms == 0);
13760
13761         emitcode ("lcall","System_%s",name);
13762 }
13763
13764 /*-----------------------------------------------------------------*/
13765 /* genSystemPoll -                                                  */
13766 /*-----------------------------------------------------------------*/
13767 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13768 {
13769         bitVect *rsave ;
13770         operand *fp;
13771
13772         assert (nparms==1);
13773         /* save registers that need to be saved */
13774         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13775                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13776
13777         fp = parms[0];
13778         aopOp (fp,ic,FALSE,FALSE);
13779         if (AOP_TYPE (fp) == AOP_IMMD) {
13780                 emitcode ("mov", "dptr,%s",
13781                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13782         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13783                 emitcode ("mov","dpl,%s",
13784                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13785                 emitcode ("mov","dph,%s",
13786                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13787                 emitcode ("mov","dpx,%s",
13788                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13789         }
13790         freeAsmop (fp, NULL, ic, FALSE);
13791
13792         emitcode ("lcall","System_%sPoll",name);
13793
13794         /* put result into place */
13795         {
13796                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13797                 if (rsym->liveFrom != rsym->liveTo) {
13798                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13799                         aopPut(IC_RESULT(ic),"a",0);
13800                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13801                 }
13802         }
13803         unsavermask(rsave);
13804 }
13805
13806 /*-----------------------------------------------------------------*/
13807 /* genSystemGetCurrentID -                                         */
13808 /*-----------------------------------------------------------------*/
13809 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13810 {
13811         assert (nparms==0);
13812
13813         emitcode ("lcall","System_GetCurrent%sId",name);
13814         /* put result into place */
13815         {
13816                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13817                 if (rsym->liveFrom != rsym->liveTo) {
13818                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13819                         aopPut(IC_RESULT(ic),"a",0);
13820                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13821                 }
13822         }
13823 }
13824
13825 /*-----------------------------------------------------------------*/
13826 /* genDjnz - generate decrement & jump if not zero instrucion      */
13827 /*-----------------------------------------------------------------*/
13828 static int
13829 genDjnz (iCode * ic, iCode * ifx)
13830 {
13831   symbol *lbl, *lbl1;
13832   if (!ifx)
13833     return 0;
13834
13835   /* if the if condition has a false label
13836      then we cannot save */
13837   if (IC_FALSE (ifx))
13838     return 0;
13839
13840   /* if the minus is not of the form a = a - 1 */
13841   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13842       !IS_OP_LITERAL (IC_RIGHT (ic)))
13843     return 0;
13844
13845   if (operandLitValue (IC_RIGHT (ic)) != 1)
13846     return 0;
13847
13848   /* if the size of this greater than one then no
13849      saving */
13850   if (getSize (operandType (IC_RESULT (ic))) > 1)
13851     return 0;
13852
13853   /* otherwise we can save BIG */
13854
13855   D (emitcode (";", "genDjnz"));
13856
13857   lbl = newiTempLabel (NULL);
13858   lbl1 = newiTempLabel (NULL);
13859
13860   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13861
13862   if (AOP_NEEDSACC(IC_RESULT(ic)))
13863   {
13864       /* If the result is accessed indirectly via
13865        * the accumulator, we must explicitly write
13866        * it back after the decrement.
13867        */
13868       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13869
13870       if (strcmp(rByte, "a"))
13871       {
13872            /* Something is hopelessly wrong */
13873            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13874                    __FILE__, __LINE__);
13875            /* We can just give up; the generated code will be inefficient,
13876             * but what the hey.
13877             */
13878            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13879            return 0;
13880       }
13881       emitcode ("dec", "%s", rByte);
13882       aopPut (IC_RESULT (ic), rByte, 0);
13883       emitcode ("jnz", "!tlabel", lbl->key + 100);
13884   }
13885   else if (IS_AOP_PREG (IC_RESULT (ic)))
13886     {
13887       emitcode ("dec", "%s",
13888                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13889       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13890       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13891       ifx->generated = 1;
13892       emitcode ("jnz", "!tlabel", lbl->key + 100);
13893     }
13894   else
13895     {
13896       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13897                 lbl->key + 100);
13898     }
13899   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13900   emitLabel (lbl);
13901   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13902   emitLabel (lbl1);
13903
13904   if (!ifx->generated)
13905       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13906   ifx->generated = 1;
13907   return 1;
13908 }
13909
13910 /*-----------------------------------------------------------------*/
13911 /* genReceive - generate code for a receive iCode                  */
13912 /*-----------------------------------------------------------------*/
13913 static void
13914 genReceive (iCode * ic)
13915 {
13916     int size = getSize (operandType (IC_RESULT (ic)));
13917     int offset = 0;
13918     int rb1off ;
13919
13920     D (emitcode (";", "genReceive"));
13921
13922     if (ic->argreg == 1)
13923     {
13924         /* first parameter */
13925         if (AOP_IS_STR(IC_RESULT(ic)))
13926         {
13927             /* Nothing to do: it's already in the proper place. */
13928             return;
13929         }
13930         else
13931         {
13932             bool useDp2;
13933
13934             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13935                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13936                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13937
13938             _G.accInUse++;
13939             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13940             _G.accInUse--;
13941
13942             /* Sanity checking... */
13943             if (AOP_USESDPTR(IC_RESULT(ic)))
13944             {
13945                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13946                         "genReceive got unexpected DPTR.");
13947             }
13948             assignResultValue (IC_RESULT (ic), NULL);
13949         }
13950     }
13951     else if (ic->argreg > 12)
13952     { /* bit parameters */
13953       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13954         {
13955           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13956           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13957           outBitC(IC_RESULT (ic));
13958         }
13959     }
13960     else
13961     {
13962         /* second receive onwards */
13963         /* this gets a little tricky since unused receives will be
13964          eliminated, we have saved the reg in the type field . and
13965          we use that to figure out which register to use */
13966         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13967         rb1off = ic->argreg;
13968         while (size--)
13969         {
13970             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13971         }
13972     }
13973     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13974 }
13975
13976 /*-----------------------------------------------------------------*/
13977 /* genDummyRead - generate code for dummy read of volatiles        */
13978 /*-----------------------------------------------------------------*/
13979 static void
13980 genDummyRead (iCode * ic)
13981 {
13982   operand *op;
13983   int size, offset;
13984
13985   D (emitcode(";", "genDummyRead"));
13986
13987   op = IC_RIGHT (ic);
13988   if (op && IS_SYMOP (op))
13989     {
13990       aopOp (op, ic, FALSE, FALSE);
13991
13992       /* if the result is a bit */
13993       if (AOP_TYPE (op) == AOP_CRY)
13994         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13995       else
13996         {
13997           /* bit variables done */
13998           /* general case */
13999           size = AOP_SIZE (op);
14000           offset = 0;
14001           while (size--)
14002           {
14003             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14004             offset++;
14005           }
14006         }
14007
14008       freeAsmop (op, NULL, ic, TRUE);
14009     }
14010
14011   op = IC_LEFT (ic);
14012   if (op && IS_SYMOP (op))
14013     {
14014       aopOp (op, ic, FALSE, FALSE);
14015
14016       /* if the result is a bit */
14017       if (AOP_TYPE (op) == AOP_CRY)
14018         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
14019       else
14020         {
14021           /* bit variables done */
14022           /* general case */
14023           size = AOP_SIZE (op);
14024           offset = 0;
14025           while (size--)
14026           {
14027             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14028             offset++;
14029           }
14030         }
14031
14032       freeAsmop (op, NULL, ic, TRUE);
14033     }
14034 }
14035
14036 /*-----------------------------------------------------------------*/
14037 /* genCritical - generate code for start of a critical sequence    */
14038 /*-----------------------------------------------------------------*/
14039 static void
14040 genCritical (iCode *ic)
14041 {
14042   symbol *tlbl = newiTempLabel (NULL);
14043
14044   D (emitcode(";", "genCritical"));
14045
14046   if (IC_RESULT (ic))
14047     {
14048       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14049       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14050       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14051       aopPut (IC_RESULT (ic), zero, 0);
14052       emitLabel (tlbl);
14053       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14054     }
14055   else
14056     {
14057       emitcode ("setb", "c");
14058       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14059       emitcode ("clr", "c");
14060       emitLabel (tlbl);
14061       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14062     }
14063 }
14064
14065 /*-----------------------------------------------------------------*/
14066 /* genEndCritical - generate code for end of a critical sequence   */
14067 /*-----------------------------------------------------------------*/
14068 static void
14069 genEndCritical (iCode *ic)
14070 {
14071   D(emitcode(";", "genEndCritical"));
14072
14073   if (IC_RIGHT (ic))
14074     {
14075       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14076       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14077         {
14078           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14079           emitcode ("mov", "ea,c");
14080         }
14081       else
14082         {
14083           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14084           emitcode ("rrc", "a");
14085           emitcode ("mov", "ea,c");
14086         }
14087       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14088     }
14089   else
14090     {
14091       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14092       emitcode ("mov", "ea,c");
14093     }
14094 }
14095
14096
14097
14098 /*-----------------------------------------------------------------*/
14099 /* genBuiltIn - calls the appropriate function to  generating code */
14100 /* for a built in function                                         */
14101 /*-----------------------------------------------------------------*/
14102 static void genBuiltIn (iCode *ic)
14103 {
14104         operand *bi_parms[MAX_BUILTIN_ARGS];
14105         int nbi_parms;
14106         iCode *bi_iCode;
14107         symbol *bif;
14108
14109         /* get all the arguments for a built in function */
14110         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14111
14112         /* which function is it */
14113         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14114         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14115                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14116         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14117                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14118         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14119                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14120         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14121                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14122         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14123                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14124         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14125                 genInp(bi_iCode,nbi_parms,bi_parms);
14126         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14127                 genOutp(bi_iCode,nbi_parms,bi_parms);
14128         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14129                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14130                 /* JavaNative builtIns */
14131         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14132                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14133         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14134                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14135         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14136                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14137         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14138                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14139         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14140                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14141         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14142                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14143         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14144                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14145         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14146                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14147         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14148                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14149         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14150                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14151         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14152                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14153         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14154                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14155         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14156                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14157         } else if (strcmp(bif->name,"MM_Free")==0) {
14158                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14159         } else if (strcmp(bif->name,"MM_Deref")==0) {
14160                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14161         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14162                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14163         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14164                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14165         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14166                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14167         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14168                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14169         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14170                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14171         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14172                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14173         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14174                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14175         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14176                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14177         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14178                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14179         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14180                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14181         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14182                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14183         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14184                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14185         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14186                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14187         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14188                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14189         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14190                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14191         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14192                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14193         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14194                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14195         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14196                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14197         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14198                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14199         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14200                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14201         } else {
14202                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14203                 return ;
14204         }
14205         return ;
14206 }
14207
14208 /*-----------------------------------------------------------------*/
14209 /* gen390Code - generate code for Dallas 390 based controllers     */
14210 /*-----------------------------------------------------------------*/
14211 void
14212 gen390Code (iCode * lic)
14213 {
14214   iCode *ic;
14215   int cln = 0;
14216
14217   _G.currentFunc = NULL;
14218   lineHead = lineCurr = NULL;
14219   dptrn[1][0] = "dpl1";
14220   dptrn[1][1] = "dph1";
14221   dptrn[1][2] = "dpx1";
14222
14223   if (options.model == MODEL_FLAT24) {
14224     fReturnSizeDS390 = 5;
14225     fReturn = fReturn24;
14226   } else {
14227     fReturnSizeDS390 = 4;
14228     fReturn = fReturn16;
14229     options.stack10bit=0;
14230   }
14231 #if 1
14232   /* print the allocation information */
14233   if (allocInfo && currFunc)
14234     printAllocInfo (currFunc, codeOutBuf);
14235 #endif
14236   /* if debug information required */
14237   if (options.debug && currFunc)
14238     {
14239       debugFile->writeFunction (currFunc, lic);
14240     }
14241   /* stack pointer name */
14242   if (options.useXstack)
14243     spname = "_spx";
14244   else
14245     spname = "sp";
14246
14247
14248   for (ic = lic; ic; ic = ic->next)
14249     {
14250       _G.current_iCode = ic;
14251
14252       if (ic->lineno && cln != ic->lineno)
14253         {
14254           if (options.debug)
14255             {
14256               debugFile->writeCLine (ic);
14257             }
14258           if (!options.noCcodeInAsm) {
14259             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14260                       printCLine(ic->filename, ic->lineno));
14261           }
14262           cln = ic->lineno;
14263         }
14264       if (options.iCodeInAsm) {
14265         const char *iLine = printILine(ic);
14266         emitcode(";", "ic:%d: %s", ic->key, iLine);
14267         dbuf_free(iLine);
14268       }
14269       /* if the result is marked as
14270          spilt and rematerializable or code for
14271          this has already been generated then
14272          do nothing */
14273       if (resultRemat (ic) || ic->generated)
14274         continue;
14275
14276       /* depending on the operation */
14277       switch (ic->op)
14278         {
14279         case '!':
14280           genNot (ic);
14281           break;
14282
14283         case '~':
14284           genCpl (ic);
14285           break;
14286
14287         case UNARYMINUS:
14288           genUminus (ic);
14289           break;
14290
14291         case IPUSH:
14292           genIpush (ic);
14293           break;
14294
14295         case IPOP:
14296           /* IPOP happens only when trying to restore a
14297              spilt live range, if there is an ifx statement
14298              following this pop then the if statement might
14299              be using some of the registers being popped which
14300              would destory the contents of the register so
14301              we need to check for this condition and handle it */
14302           if (ic->next &&
14303               ic->next->op == IFX &&
14304               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14305             genIfx (ic->next, ic);
14306           else
14307             genIpop (ic);
14308           break;
14309
14310         case CALL:
14311           genCall (ic);
14312           break;
14313
14314         case PCALL:
14315           genPcall (ic);
14316           break;
14317
14318         case FUNCTION:
14319           genFunction (ic);
14320           break;
14321
14322         case ENDFUNCTION:
14323           genEndFunction (ic);
14324           break;
14325
14326         case RETURN:
14327           genRet (ic);
14328           break;
14329
14330         case LABEL:
14331           genLabel (ic);
14332           break;
14333
14334         case GOTO:
14335           genGoto (ic);
14336           break;
14337
14338         case '+':
14339           genPlus (ic);
14340           break;
14341
14342         case '-':
14343           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14344             genMinus (ic);
14345           break;
14346
14347         case '*':
14348           genMult (ic);
14349           break;
14350
14351         case '/':
14352           genDiv (ic);
14353           break;
14354
14355         case '%':
14356           genMod (ic);
14357           break;
14358
14359         case '>':
14360           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14361           break;
14362
14363         case '<':
14364           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14365           break;
14366
14367         case LE_OP:
14368         case GE_OP:
14369         case NE_OP:
14370
14371           /* note these two are xlated by algebraic equivalence
14372              during parsing SDCC.y */
14373           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14374                   "got '>=' or '<=' shouldn't have come here");
14375           break;
14376
14377         case EQ_OP:
14378           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14379           break;
14380
14381         case AND_OP:
14382           genAndOp (ic);
14383           break;
14384
14385         case OR_OP:
14386           genOrOp (ic);
14387           break;
14388
14389         case '^':
14390           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14391           break;
14392
14393         case '|':
14394           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14395           break;
14396
14397         case BITWISEAND:
14398           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14399           break;
14400
14401         case INLINEASM:
14402           genInline (ic);
14403           break;
14404
14405         case RRC:
14406           genRRC (ic);
14407           break;
14408
14409         case RLC:
14410           genRLC (ic);
14411           break;
14412
14413         case GETHBIT:
14414           genGetHbit (ic);
14415           break;
14416
14417         case LEFT_OP:
14418           genLeftShift (ic);
14419           break;
14420
14421         case RIGHT_OP:
14422           genRightShift (ic);
14423           break;
14424
14425         case GET_VALUE_AT_ADDRESS:
14426           genPointerGet (ic,
14427                          hasInc (IC_LEFT (ic), ic,
14428                                  getSize (operandType (IC_RESULT (ic)))));
14429           break;
14430
14431         case '=':
14432           if (POINTER_SET (ic))
14433             genPointerSet (ic,
14434                            hasInc (IC_RESULT (ic), ic,
14435                                    getSize (operandType (IC_RIGHT (ic)))));
14436           else
14437             genAssign (ic);
14438           break;
14439
14440         case IFX:
14441           genIfx (ic, NULL);
14442           break;
14443
14444         case ADDRESS_OF:
14445           genAddrOf (ic);
14446           break;
14447
14448         case JUMPTABLE:
14449           genJumpTab (ic);
14450           break;
14451
14452         case CAST:
14453           genCast (ic);
14454           break;
14455
14456         case RECEIVE:
14457           genReceive (ic);
14458           break;
14459
14460         case SEND:
14461           if (ic->builtinSEND)
14462             genBuiltIn(ic);
14463           else
14464             addSet (&_G.sendSet, ic);
14465           break;
14466
14467         case DUMMY_READ_VOLATILE:
14468           genDummyRead (ic);
14469           break;
14470
14471         case CRITICAL:
14472           genCritical (ic);
14473           break;
14474
14475         case ENDCRITICAL:
14476           genEndCritical (ic);
14477           break;
14478
14479         case SWAP:
14480           genSwap (ic);
14481           break;
14482
14483 #if 0 // obsolete, and buggy for != xdata
14484         case ARRAYINIT:
14485             genArrayInit(ic);
14486             break;
14487 #endif
14488
14489         default:
14490             /* This should never happen, right? */
14491             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n",
14492                     ic->op, ic->op, __FILE__, __LINE__);
14493             ic = ic;
14494         }
14495     }
14496
14497
14498   /* now we are ready to call the
14499      peep hole optimizer */
14500   if (!options.nopeep)
14501     peepHole (&lineHead);
14502
14503   /* now do the actual printing */
14504   printLine (lineHead, codeOutBuf);
14505   return;
14506 }