* src/SDCC.y, src/SDCCast.c, src/SDCCcse.c, src/SDCCglue.c, src/SDCCicode.c,
[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   sym_link *type = operandType (op);
1951
1952   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1953     {
1954       return 1;
1955     }
1956   return 0;
1957 }
1958
1959 /*-----------------------------------------------------------------*/
1960 /* getDataSize - get the operand data size                         */
1961 /*-----------------------------------------------------------------*/
1962 static int
1963 getDataSize (operand * op)
1964 {
1965   int size;
1966   size = AOP_SIZE (op);
1967   if (size == GPTRSIZE)
1968     {
1969       sym_link *type = operandType (op);
1970       if (IS_GENPTR (type))
1971         {
1972           /* generic pointer; arithmetic operations
1973            * should ignore the high byte (pointer type).
1974            */
1975           size--;
1976         }
1977     }
1978   return size;
1979 }
1980
1981 /*-----------------------------------------------------------------*/
1982 /* outAcc - output Acc                                             */
1983 /*-----------------------------------------------------------------*/
1984 static void
1985 outAcc (operand * result)
1986 {
1987   int size, offset;
1988   size = getDataSize (result);
1989   if (size)
1990     {
1991       aopPut (result, "a", 0);
1992       size--;
1993       offset = 1;
1994       /* unsigned or positive */
1995       while (size--)
1996         {
1997           aopPut (result, zero, offset++);
1998         }
1999     }
2000 }
2001
2002 /*-----------------------------------------------------------------*/
2003 /* outBitC - output a bit C                                        */
2004 /*-----------------------------------------------------------------*/
2005 static void
2006 outBitC (operand * result)
2007 {
2008   /* if the result is bit */
2009   if (AOP_TYPE (result) == AOP_CRY)
2010     {
2011       aopPut (result, "c", 0);
2012     }
2013   else
2014     {
2015       emitcode ("clr", "a");
2016       emitcode ("rlc", "a");
2017       outAcc (result);
2018     }
2019 }
2020
2021 /*-----------------------------------------------------------------*/
2022 /* toBoolean - emit code for orl a,operator(sizeop)                */
2023 /*-----------------------------------------------------------------*/
2024 static void
2025 toBoolean (operand * oper)
2026 {
2027   int  size = AOP_SIZE (oper) - 1;
2028   int  offset = 1;
2029   bool pushedB;
2030
2031   /* The generic part of a generic pointer should
2032    * not participate in it's truth value.
2033    *
2034    * i.e. 0x10000000 is zero.
2035    */
2036   if (opIsGptr (oper))
2037     {
2038       D (emitcode (";", "toBoolean: generic ptr special case."));
2039       size--;
2040     }
2041
2042   _startLazyDPSEvaluation ();
2043   MOVA (aopGet (oper, 0, FALSE, FALSE, NULL));
2044   if (AOP_NEEDSACC (oper) && size && (AOP (oper)->type != AOP_ACC))
2045     {
2046       pushedB = pushB ();
2047       emitcode("mov", "b,a");
2048       while (--size)
2049         {
2050           MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2051           emitcode ("orl", "b,a");
2052         }
2053       MOVA (aopGet (oper, offset++, FALSE, FALSE, NULL));
2054       emitcode ("orl", "a,b");
2055       popB (pushedB);
2056     }
2057   else
2058     {
2059       while (size--)
2060         {
2061           emitcode ("orl", "a,%s",
2062                     aopGet (oper, offset++, FALSE, FALSE, NULL));
2063         }
2064     }
2065   _endLazyDPSEvaluation ();
2066 }
2067
2068
2069 /*-----------------------------------------------------------------*/
2070 /* genNot - generate code for ! operation                          */
2071 /*-----------------------------------------------------------------*/
2072 static void
2073 genNot (iCode * ic)
2074 {
2075   symbol *tlbl;
2076
2077   D (emitcode (";", "genNot"));
2078
2079   /* assign asmOps to operand & result */
2080   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2081   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2082
2083   /* if in bit space then a special case */
2084   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2085     {
2086       /* if left==result then cpl bit */
2087       if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
2088         {
2089           emitcode ("cpl", "%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2090         }
2091       else
2092         {
2093           emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2094           emitcode ("cpl", "c");
2095           outBitC (IC_RESULT (ic));
2096         }
2097       goto release;
2098     }
2099
2100   toBoolean (IC_LEFT (ic));
2101
2102   /* set C, if a == 0 */
2103   tlbl = newiTempLabel (NULL);
2104   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
2105   emitLabel (tlbl);
2106   outBitC (IC_RESULT (ic));
2107
2108 release:
2109   /* release the aops */
2110   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2111   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2112 }
2113
2114
2115 /*-----------------------------------------------------------------*/
2116 /* genCpl - generate code for complement                           */
2117 /*-----------------------------------------------------------------*/
2118 static void
2119 genCpl (iCode * ic)
2120 {
2121   int offset = 0;
2122   int size;
2123   symbol *tlbl;
2124   sym_link *letype = getSpec (operandType (IC_LEFT (ic)));
2125
2126   D(emitcode (";", "genCpl"));
2127
2128   /* assign asmOps to operand & result */
2129   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2130   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
2131
2132   /* special case if in bit space */
2133   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
2134     {
2135       char *l;
2136
2137       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY ||
2138           (SPEC_USIGN (letype) && IS_CHAR (letype)))
2139         {
2140           /* promotion rules are responsible for this strange result:
2141              bit -> int -> ~int -> bit
2142              uchar -> int -> ~int -> bit
2143           */
2144           emitcode ("setb", "%s", IC_RESULT (ic)->aop->aopu.aop_dir);
2145           goto release;
2146         }
2147
2148       tlbl=newiTempLabel(NULL);
2149       l = aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL);
2150       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_ACC && offset == 0) ||
2151           AOP_TYPE (IC_LEFT (ic)) == AOP_REG ||
2152           IS_AOP_PREG (IC_LEFT (ic)))
2153         {
2154           emitcode ("cjne", "%s,#0xFF,%05d$", l, tlbl->key + 100);
2155         }
2156       else
2157         {
2158           MOVA (l);
2159           emitcode ("cjne", "a,#0xFF,%05d$", tlbl->key + 100);
2160         }
2161       emitLabel (tlbl);
2162       outBitC (IC_RESULT(ic));
2163       goto release;
2164     }
2165
2166   size = AOP_SIZE (IC_RESULT (ic));
2167   _startLazyDPSEvaluation ();
2168   while (size--)
2169     {
2170       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2171       MOVA (l);
2172       emitcode ("cpl", "a");
2173       aopPut (IC_RESULT (ic), "a", offset++);
2174     }
2175   _endLazyDPSEvaluation ();
2176
2177
2178 release:
2179   /* release the aops */
2180   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2181   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2182 }
2183
2184 /*-----------------------------------------------------------------*/
2185 /* genUminusFloat - unary minus for floating points                */
2186 /*-----------------------------------------------------------------*/
2187 static void
2188 genUminusFloat (operand * op, operand * result)
2189 {
2190   int size, offset = 0;
2191   char *l;
2192
2193   D (emitcode (";", "genUminusFloat"));
2194
2195   /* for this we just copy and then flip the bit */
2196
2197   _startLazyDPSEvaluation ();
2198   size = AOP_SIZE (op) - 1;
2199
2200   while (size--)
2201     {
2202       aopPut (result,
2203               aopGet (op, offset, FALSE, FALSE, NULL),
2204               offset);
2205       offset++;
2206     }
2207
2208   l = aopGet (op, offset, FALSE, FALSE, NULL);
2209   MOVA (l);
2210
2211   emitcode ("cpl", "acc.7");
2212   aopPut (result, "a", offset);
2213   _endLazyDPSEvaluation ();
2214 }
2215
2216 /*-----------------------------------------------------------------*/
2217 /* genUminus - unary minus code generation                         */
2218 /*-----------------------------------------------------------------*/
2219 static void
2220 genUminus (iCode * ic)
2221 {
2222   int offset, size;
2223   sym_link *optype;
2224
2225   D (emitcode (";", "genUminus"));
2226
2227   /* assign asmops */
2228   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2229   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2230
2231   /* if both in bit space then special
2232      case */
2233   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2234       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2235     {
2236
2237       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2238       emitcode ("cpl", "c");
2239       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2240       goto release;
2241     }
2242
2243   optype = operandType (IC_LEFT (ic));
2244
2245   /* if float then do float stuff */
2246   if (IS_FLOAT (optype))
2247     {
2248       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2249       goto release;
2250     }
2251
2252   /* otherwise subtract from zero */
2253   size = AOP_SIZE (IC_LEFT (ic));
2254   offset = 0;
2255   _startLazyDPSEvaluation ();
2256   while (size--)
2257     {
2258       char *l = aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL);
2259       if (!strcmp (l, "a"))
2260         {
2261           if (offset == 0)
2262             SETC;
2263           emitcode ("cpl", "a");
2264           emitcode ("addc", "a,#0");
2265         }
2266       else
2267         {
2268           if (offset == 0)
2269             CLRC;
2270           emitcode ("clr", "a");
2271           emitcode ("subb", "a,%s", l);
2272         }
2273       aopPut (IC_RESULT (ic), "a", offset++);
2274     }
2275   _endLazyDPSEvaluation ();
2276
2277   /* if any remaining bytes in the result */
2278   /* we just need to propagate the sign   */
2279   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2280     {
2281       emitcode ("rlc", "a");
2282       emitcode ("subb", "a,acc");
2283       while (size--)
2284         aopPut (IC_RESULT (ic), "a", offset++);
2285     }
2286
2287 release:
2288   /* release the aops */
2289   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2290   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2291 }
2292
2293 /*-----------------------------------------------------------------*/
2294 /* savermask - saves registers in the mask                         */
2295 /*-----------------------------------------------------------------*/
2296 static void savermask(bitVect *rs_mask)
2297 {
2298   int i;
2299
2300   if (options.useXstack)
2301     {
2302       if (bitVectBitValue (rs_mask, R0_IDX))
2303           emitcode ("mov", "b,r0");
2304       emitcode ("mov", "r0,%s", spname);
2305       for (i = 0; i < ds390_nRegs; i++)
2306         {
2307           if (bitVectBitValue (rs_mask, i))
2308             {
2309               if (i == R0_IDX)
2310                   emitcode ("mov", "a,b");
2311               else
2312                   emitcode ("mov", "a,%s", REG_WITH_INDEX (i)->name);
2313               emitcode ("movx", "@r0,a");
2314               emitcode ("inc", "r0");
2315             }
2316         }
2317       emitcode ("mov", "%s,r0", spname);
2318       if (bitVectBitValue (rs_mask, R0_IDX))
2319           emitcode ("mov", "r0,b");
2320     }
2321   else
2322     {
2323       bool bits_pushed = FALSE;
2324       for (i = 0; i < ds390_nRegs; i++)
2325         {
2326           if (bitVectBitValue (rs_mask, i))
2327             {
2328               bits_pushed = pushReg (i, bits_pushed);
2329             }
2330         }
2331     }
2332 }
2333
2334 /*-----------------------------------------------------------------*/
2335 /* saveRegisters - will look for a call and save the registers     */
2336 /*-----------------------------------------------------------------*/
2337 static void
2338 saveRegisters (iCode * lic)
2339 {
2340   iCode *ic;
2341   bitVect *rsave;
2342
2343   /* look for call */
2344   for (ic = lic; ic; ic = ic->next)
2345     if (ic->op == CALL || ic->op == PCALL)
2346       break;
2347
2348   if (!ic)
2349     {
2350       fprintf (stderr, "found parameter push with no function call\n");
2351       return;
2352     }
2353
2354   /* if the registers have been saved already or don't need to be then
2355      do nothing */
2356   if (ic->regsSaved
2357       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2358     return;
2359
2360   /* special case if DPTR alive across a function call then must save it
2361      even though callee saves */
2362   if (IS_SYMOP(IC_LEFT(ic)) &&
2363       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type))
2364     {
2365       int i;
2366       rsave = newBitVect(ic->rMask->size);
2367       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2368           if (bitVectBitValue(ic->rMask,i))
2369               rsave = bitVectSetBit(rsave,i);
2370       }
2371       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2372     }
2373   else
2374     {
2375       /* save the registers in use at this time but skip the
2376          ones for the result */
2377       rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2378                              ds390_rUmaskForOp (IC_RESULT(ic)));
2379     }
2380   ic->regsSaved = 1;
2381   savermask(rsave);
2382 }
2383
2384 /*-----------------------------------------------------------------*/
2385 /* usavermask - restore registers with mask                        */
2386 /*-----------------------------------------------------------------*/
2387 static void unsavermask(bitVect *rs_mask)
2388 {
2389   int i;
2390
2391   if (options.useXstack)
2392     {
2393       emitcode ("mov", "r0,%s", spname);
2394       for (i = ds390_nRegs; i >= 0; i--)
2395         {
2396           if (bitVectBitValue (rs_mask, i))
2397             {
2398               regs * reg = REG_WITH_INDEX (i);
2399               emitcode ("dec", "r0");
2400               emitcode ("movx", "a,@r0");
2401               if (i == R0_IDX)
2402                 {
2403                   emitcode ("push", "acc");
2404                 }
2405               else
2406                 {
2407                   emitcode ("mov", "%s,a", reg->name);
2408                 }
2409             }
2410         }
2411       emitcode ("mov", "%s,r0", spname);
2412       if (bitVectBitValue (rs_mask, R0_IDX))
2413         {
2414           emitcode ("pop", "ar0");
2415         }
2416     }
2417   else
2418     {
2419       bool bits_popped = FALSE;
2420       for (i = ds390_nRegs; i >= 0; i--)
2421         {
2422           if (bitVectBitValue (rs_mask, i))
2423             {
2424               bits_popped = popReg (i, bits_popped);
2425             }
2426         }
2427     }
2428 }
2429
2430 /*-----------------------------------------------------------------*/
2431 /* unsaveRegisters - pop the pushed registers                      */
2432 /*-----------------------------------------------------------------*/
2433 static void
2434 unsaveRegisters (iCode * ic)
2435 {
2436   bitVect *rsave;
2437
2438   if (IS_SYMOP(IC_LEFT (ic)) &&
2439       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2440       int i;
2441       rsave = newBitVect(ic->rMask->size);
2442       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2443           if (bitVectBitValue(ic->rMask,i))
2444               rsave = bitVectSetBit(rsave,i);
2445       }
2446       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2447   } else {
2448     /* restore the registers in use at this time but skip the
2449        ones for the result */
2450     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2451                            ds390_rUmaskForOp (IC_RESULT(ic)));
2452   }
2453   unsavermask(rsave);
2454 }
2455
2456
2457 /*-----------------------------------------------------------------*/
2458 /* pushSide -                */
2459 /*-----------------------------------------------------------------*/
2460 static void
2461 pushSide (operand * oper, int size)
2462 {
2463   int offset = 0;
2464   _startLazyDPSEvaluation ();
2465   while (size--)
2466     {
2467       char *l = aopGet (oper, offset++, FALSE, TRUE, NULL);
2468       if (AOP_TYPE (oper) != AOP_REG &&
2469           AOP_TYPE (oper) != AOP_DIR &&
2470           strcmp (l, "a"))
2471         {
2472           MOVA (l);
2473           emitcode ("push", "acc");
2474         }
2475       else
2476         {
2477           emitcode ("push", "%s", l);
2478         }
2479     }
2480   _endLazyDPSEvaluation ();
2481 }
2482
2483 /*-----------------------------------------------------------------*/
2484 /* assignResultValue - also indicates if acc is in use afterwards  */
2485 /*-----------------------------------------------------------------*/
2486 static bool
2487 assignResultValue (operand * oper, operand * func)
2488 {
2489   int offset = 0;
2490   unsigned size = AOP_SIZE (oper);
2491   bool accuse = FALSE;
2492   bool pushedA = FALSE;
2493
2494   if (func && IS_BIT (OP_SYM_ETYPE (func)))
2495     {
2496       outBitC (oper);
2497       return FALSE;
2498     }
2499
2500   if (size == fReturnSizeDS390)
2501   {
2502       /* I don't think this case can ever happen... */
2503       /* ACC is the last part of this. If writing the result
2504        * uses ACC, we must preserve it.
2505        */
2506       if (AOP_NEEDSACC(oper))
2507       {
2508           emitcode(";", "assignResultValue special case for ACC.");
2509           emitcode("push", "acc");
2510           pushedA = TRUE;
2511           size--;
2512       }
2513   }
2514
2515   _startLazyDPSEvaluation ();
2516   while (size--)
2517     {
2518       accuse |= aopPut (oper, fReturn[offset], offset);
2519       offset++;
2520     }
2521   _endLazyDPSEvaluation ();
2522
2523   if (pushedA)
2524     {
2525         emitcode ("pop", "acc");
2526         accuse |= aopPut (oper, "a", offset);
2527     }
2528   return accuse;
2529 }
2530
2531
2532 /*-----------------------------------------------------------------*/
2533 /* genXpush - pushes onto the external stack                       */
2534 /*-----------------------------------------------------------------*/
2535 static void
2536 genXpush (iCode * ic)
2537 {
2538   asmop *aop = newAsmop (0);
2539   regs *r;
2540   int size, offset = 0;
2541
2542   D (emitcode (";", "genXpush"));
2543
2544   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2545   r = getFreePtr (ic, &aop, FALSE);
2546
2547   size = AOP_SIZE (IC_LEFT (ic));
2548
2549   if (size == 1)
2550     {
2551       MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
2552       emitcode ("mov", "%s,_spx", r->name);
2553       emitcode ("inc", "_spx"); // allocate space first
2554       emitcode ("movx", "@%s,a", r->name);
2555     }
2556   else
2557     {
2558       // allocate space first
2559       emitcode ("mov", "%s,_spx", r->name);
2560       MOVA (r->name);
2561       emitcode ("add", "a,#%d", size);
2562       emitcode ("mov", "_spx,a");
2563
2564       _startLazyDPSEvaluation ();
2565       while (size--)
2566         {
2567           MOVA (aopGet (IC_LEFT (ic), offset++, FALSE, FALSE, NULL));
2568           emitcode ("movx", "@%s,a", r->name);
2569           emitcode ("inc", "%s", r->name);
2570         }
2571       _endLazyDPSEvaluation ();
2572     }
2573
2574   freeAsmop (NULL, aop, ic, TRUE);
2575   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2576 }
2577
2578 /*-----------------------------------------------------------------*/
2579 /* genIpush - generate code for pushing this gets a little complex  */
2580 /*-----------------------------------------------------------------*/
2581 static void
2582 genIpush (iCode * ic)
2583 {
2584   int size, offset = 0;
2585   char *l;
2586   char *prev = "";
2587
2588   D (emitcode (";", "genIpush"));
2589
2590   /* if this is not a parm push : ie. it is spill push
2591      and spill push is always done on the local stack */
2592   if (!ic->parmPush)
2593     {
2594
2595       /* and the item is spilt then do nothing */
2596       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2597         return;
2598
2599       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2600       size = AOP_SIZE (IC_LEFT (ic));
2601       /* push it on the stack */
2602       _startLazyDPSEvaluation ();
2603       while (size--)
2604         {
2605           l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2606           if (*l == '#')
2607             {
2608               MOVA (l);
2609               l = "acc";
2610             }
2611           emitcode ("push", "%s", l);
2612         }
2613       _endLazyDPSEvaluation ();
2614       return;
2615     }
2616
2617   /* this is a parameter push: in this case we call
2618      the routine to find the call and save those
2619      registers that need to be saved */
2620   saveRegisters (ic);
2621
2622   /* if use external stack then call the external
2623      stack pushing routine */
2624   if (options.useXstack)
2625     {
2626       genXpush (ic);
2627       return;
2628     }
2629
2630   /* then do the push */
2631   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2632
2633   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2634   size = AOP_SIZE (IC_LEFT (ic));
2635
2636   _startLazyDPSEvaluation ();
2637   while (size--)
2638     {
2639       l = aopGet (IC_LEFT (ic), offset++, FALSE, TRUE, NULL);
2640       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2641           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2642           strcmp (l, "acc"))
2643         {
2644           if (strcmp (l, prev) || *l == '@')
2645             MOVA (l);
2646           emitcode ("push", "acc");
2647         }
2648       else
2649         {
2650             emitcode ("push", "%s", l);
2651         }
2652       prev = l;
2653     }
2654   _endLazyDPSEvaluation ();
2655
2656   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2657 }
2658
2659 /*-----------------------------------------------------------------*/
2660 /* genIpop - recover the registers: can happen only for spilling   */
2661 /*-----------------------------------------------------------------*/
2662 static void
2663 genIpop (iCode * ic)
2664 {
2665   int size, offset;
2666
2667   D (emitcode (";", "genIpop"));
2668
2669   /* if the temp was not pushed then */
2670   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2671     return;
2672
2673   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2674   size = AOP_SIZE (IC_LEFT (ic));
2675   offset = (size - 1);
2676   _startLazyDPSEvaluation ();
2677   while (size--)
2678     {
2679       emitcode ("pop", "%s", aopGet (IC_LEFT (ic), offset--,
2680                                      FALSE, TRUE, NULL));
2681     }
2682   _endLazyDPSEvaluation ();
2683
2684   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2685 }
2686
2687 /*-----------------------------------------------------------------*/
2688 /* saveRBank - saves an entire register bank on the stack          */
2689 /*-----------------------------------------------------------------*/
2690 static void
2691 saveRBank (int bank, iCode * ic, bool pushPsw)
2692 {
2693   int i;
2694   int count = 8 + (ds390_nBitRegs/8) + (pushPsw ? 1 : 0);
2695   asmop *aop = NULL;
2696   regs *r = NULL;
2697
2698   if (options.useXstack)
2699     {
2700       if (!ic)
2701         {
2702           /* Assume r0 is available for use. */
2703           r = REG_WITH_INDEX (R0_IDX);;
2704         }
2705       else
2706         {
2707           aop = newAsmop (0);
2708           r = getFreePtr (ic, &aop, FALSE);
2709         }
2710       // allocate space first
2711       emitcode ("mov", "%s,_spx", r->name);
2712       MOVA (r->name);
2713       emitcode ("add", "a,#%d", count);
2714       emitcode ("mov", "_spx,a");
2715     }
2716
2717   for (i = 0; i < 8; i++) /* only R0-R7 needs saving */
2718     {
2719       if (options.useXstack)
2720         {
2721           emitcode ("mov", "a,(%s+%d)",
2722                     regs390[i].base, 8 * bank + regs390[i].offset);
2723           emitcode ("movx", "@%s,a", r->name);
2724           if (--count)
2725             emitcode ("inc", "%s", r->name);
2726         }
2727       else
2728         emitcode ("push", "(%s+%d)",
2729                   regs390[i].base, 8 * bank + regs390[i].offset);
2730     }
2731
2732   if (ds390_nBitRegs > 0)
2733     {
2734       if (options.useXstack)
2735         {
2736           emitcode ("mov", "a,bits");
2737           emitcode ("movx", "@%s,a", r->name);
2738           if (--count)
2739             emitcode ("inc", "%s", r->name);
2740         }
2741       else
2742         {
2743           emitcode ("push", "bits");
2744         }
2745       BitBankUsed = 1;
2746     }
2747
2748   if (pushPsw)
2749     {
2750       if (options.useXstack)
2751         {
2752           emitcode ("mov", "a,psw");
2753           emitcode ("movx", "@%s,a", r->name);
2754         }
2755       else
2756       {
2757         emitcode ("push", "psw");
2758       }
2759
2760       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2761     }
2762
2763   if (aop)
2764     {
2765       freeAsmop (NULL, aop, ic, TRUE);
2766     }
2767
2768   if (ic)
2769   {
2770     ic->bankSaved = 1;
2771   }
2772 }
2773
2774 /*-----------------------------------------------------------------*/
2775 /* unsaveRBank - restores the register bank from stack             */
2776 /*-----------------------------------------------------------------*/
2777 static void
2778 unsaveRBank (int bank, iCode * ic, bool popPsw)
2779 {
2780   int i;
2781   asmop *aop = NULL;
2782   regs *r = NULL;
2783
2784   if (options.useXstack)
2785     {
2786       if (!ic)
2787         {
2788           /* Assume r0 is available for use. */
2789           r = REG_WITH_INDEX (R0_IDX);;
2790         }
2791       else
2792         {
2793           aop = newAsmop (0);
2794           r = getFreePtr (ic, &aop, FALSE);
2795         }
2796       emitcode ("mov", "%s,_spx", r->name);
2797     }
2798
2799   if (popPsw)
2800     {
2801       if (options.useXstack)
2802         {
2803           emitcode ("dec", "%s", r->name);
2804           emitcode ("movx", "a,@%s", r->name);
2805           emitcode ("mov", "psw,a");
2806         }
2807       else
2808       {
2809         emitcode ("pop", "psw");
2810       }
2811     }
2812
2813   if (ds390_nBitRegs > 0)
2814     {
2815       if (options.useXstack)
2816         {
2817           emitcode ("dec", "%s", r->name);
2818           emitcode ("movx", "a,@%s", r->name);
2819           emitcode ("mov", "bits,a");
2820         }
2821       else
2822         {
2823           emitcode ("pop", "bits");
2824         }
2825     }
2826
2827   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2828     {
2829       if (options.useXstack)
2830         {
2831           emitcode ("dec", "%s", r->name);
2832           emitcode ("movx", "a,@%s", r->name);
2833           emitcode ("mov", "(%s+%d),a",
2834                     regs390[i].base, 8 * bank + regs390[i].offset);
2835         }
2836       else
2837         {
2838           emitcode ("pop", "(%s+%d)",
2839                     regs390[i].base, 8 * bank + regs390[i].offset);
2840         }
2841     }
2842
2843   if (options.useXstack)
2844     {
2845       emitcode ("mov", "_spx,%s", r->name);
2846     }
2847
2848   if (aop)
2849     {
2850       freeAsmop (NULL, aop, ic, TRUE);
2851     }
2852 }
2853
2854 /*-----------------------------------------------------------------*/
2855 /* genSend - gen code for SEND                                     */
2856 /*-----------------------------------------------------------------*/
2857 static void genSend(set *sendSet)
2858 {
2859   iCode *sic;
2860   int bit_count = 0;
2861   int sendCount = 0 ;
2862   static int rb1_count = 0;
2863
2864   /* first we do all bit parameters */
2865   for (sic = setFirstItem (sendSet); sic;
2866        sic = setNextItem (sendSet))
2867     {
2868       if (sic->argreg > 12)
2869         {
2870           int bit = sic->argreg-13;
2871
2872           aopOp (IC_LEFT (sic), sic, FALSE,
2873                  (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2874
2875           /* if left is a literal then
2876              we know what the value is */
2877           if (AOP_TYPE (IC_LEFT (sic)) == AOP_LIT)
2878             {
2879               if (((int) operandLitValue (IC_LEFT (sic))))
2880                   emitcode ("setb", "b[%d]", bit);
2881               else
2882                   emitcode ("clr", "b[%d]", bit);
2883             }
2884           else if (AOP_TYPE (IC_LEFT (sic)) == AOP_CRY)
2885             {
2886               char *l = AOP (IC_LEFT (sic))->aopu.aop_dir;
2887                 if (strcmp (l, "c"))
2888                     emitcode ("mov", "c,%s", l);
2889                 emitcode ("mov", "b[%d],c", bit);
2890             }
2891           else
2892             {
2893               /* we need to or */
2894               toBoolean (IC_LEFT (sic));
2895               /* set C, if a >= 1 */
2896               emitcode ("add", "a,#0xff");
2897               emitcode ("mov", "b[%d],c", bit);
2898             }
2899           bit_count++;
2900           BitBankUsed = 1;
2901
2902           freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2903         }
2904     }
2905
2906   if (bit_count)
2907     {
2908       saveRegisters (setFirstItem (sendSet));
2909       emitcode ("mov", "bits,b");
2910     }
2911
2912   /* then we do all other parameters */
2913   for (sic = setFirstItem (sendSet); sic;
2914        sic = setNextItem (sendSet))
2915     {
2916       if (sic->argreg <= 12)
2917       {
2918         int size, offset = 0;
2919
2920         size = getSize (operandType (IC_LEFT (sic)));
2921         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2922         if (sendCount == 0) { /* first parameter */
2923             // we know that dpl(hxb) is the result, so
2924             rb1_count = 0 ;
2925             _startLazyDPSEvaluation ();
2926             if (size>1) {
2927                 aopOp (IC_LEFT (sic), sic, FALSE,
2928                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2929             } else {
2930                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2931             }
2932             while (size--)
2933               {
2934                 char *l = aopGet (IC_LEFT (sic), offset, FALSE, FALSE, NULL);
2935                 if (strcmp (l, fReturn[offset]))
2936                   {
2937                     emitcode ("mov", "%s,%s", fReturn[offset], l);
2938                   }
2939                 offset++;
2940               }
2941             _endLazyDPSEvaluation ();
2942             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2943             rb1_count =0;
2944         } else { /* if more parameter in registers */
2945             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2946             while (size--) {
2947                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (IC_LEFT (sic), offset++,
2948                                                                 FALSE, FALSE, NULL));
2949             }
2950             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2951         }
2952         sendCount++;
2953       }
2954     }
2955 }
2956
2957 static void
2958 adjustEsp(const char *reg)
2959 {
2960     emitcode ("anl","%s,#3", reg);
2961     if (TARGET_IS_DS400)
2962     {
2963         emitcode ("orl","%s,#!constbyte",
2964                   reg,
2965                   (options.stack_loc >> 8) & 0xff);
2966     }
2967 }
2968
2969 /*-----------------------------------------------------------------*/
2970 /* selectRegBank - emit code to select the register bank           */
2971 /*-----------------------------------------------------------------*/
2972 static void
2973 selectRegBank (short bank, bool keepFlags)
2974 {
2975   /* if f.e. result is in carry */
2976   if (keepFlags)
2977     {
2978       emitcode ("anl", "psw,#0xE7");
2979       if (bank)
2980         emitcode ("orl", "psw,#0x%02x", (bank << 3) & 0xff);
2981     }
2982   else
2983     {
2984       emitcode ("mov", "psw,#0x%02x", (bank << 3) & 0xff);
2985     }
2986 }
2987
2988 /*-----------------------------------------------------------------*/
2989 /* genCall - generates a call statement                            */
2990 /*-----------------------------------------------------------------*/
2991 static void
2992 genCall (iCode * ic)
2993 {
2994   sym_link *dtype;
2995   sym_link *etype;
2996   bool restoreBank = FALSE;
2997   bool swapBanks = FALSE;
2998   bool accuse = FALSE;
2999   bool accPushed = FALSE;
3000   bool resultInF0 = FALSE;
3001   bool assignResultGenerated = FALSE;
3002
3003   D (emitcode (";", "genCall"));
3004
3005   /* if we are calling a not _naked function that is not using
3006      the same register bank then we need to save the
3007      destination registers on the stack */
3008   dtype = operandType (IC_LEFT (ic));
3009   etype = getSpec(dtype);
3010   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3011       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
3012       IFFUNC_ISISR (currFunc->type))
3013   {
3014       if (!ic->bankSaved)
3015       {
3016            /* This is unexpected; the bank should have been saved in
3017             * genFunction.
3018             */
3019            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3020            restoreBank = TRUE;
3021       }
3022       swapBanks = TRUE;
3023   }
3024
3025   /* if caller saves & we have not saved then */
3026   if (!ic->regsSaved)
3027       saveRegisters (ic);
3028
3029   /* if send set is not empty then assign */
3030   /* We've saved all the registers we care about;
3031   * therefore, we may clobber any register not used
3032   * in the calling convention (i.e. anything not in
3033   * fReturn.
3034   */
3035   if (_G.sendSet)
3036     {
3037         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
3038             genSend(reverseSet(_G.sendSet));
3039         } else {
3040             genSend(_G.sendSet);
3041         }
3042       _G.sendSet = NULL;
3043     }
3044
3045   if (swapBanks)
3046     {
3047       emitcode ("mov", "psw,#!constbyte",
3048          ((FUNC_REGBANK(dtype)) << 3) & 0xff);
3049     }
3050
3051   /* make the call */
3052   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
3053                             OP_SYMBOL (IC_LEFT (ic))->rname :
3054                             OP_SYMBOL (IC_LEFT (ic))->name));
3055
3056   if (swapBanks)
3057     {
3058       selectRegBank (FUNC_REGBANK(currFunc->type), IS_BIT (etype));
3059     }
3060
3061   /* if we need assign a result value */
3062   if ((IS_ITEMP (IC_RESULT (ic)) &&
3063        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3064        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3065         OP_SYMBOL (IC_RESULT (ic))->accuse ||
3066         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3067       IS_TRUE_SYMOP (IC_RESULT (ic)))
3068     {
3069       if (isOperandInFarSpace (IC_RESULT (ic))
3070           && getSize (operandType (IC_RESULT (ic))) <= 2)
3071         {
3072           int size = getSize (operandType (IC_RESULT (ic)));
3073           bool pushedB = FALSE;
3074
3075           /* Special case for 1 or 2 byte return in far space. */
3076           MOVA (fReturn[0]);
3077           if (size > 1)
3078             {
3079               pushedB = pushB ();
3080               emitcode ("mov", "b,%s", fReturn[1]);
3081             }
3082
3083           _G.accInUse++;
3084           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3085           _G.accInUse--;
3086
3087           popB (pushedB);
3088
3089           aopPut (IC_RESULT (ic), "a", 0);
3090
3091           if (size > 1)
3092             {
3093               aopPut (IC_RESULT (ic), "b", 1);
3094             }
3095           assignResultGenerated = TRUE;
3096           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3097         }
3098       else
3099         {
3100           bool pushedB = pushB ();
3101           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3102           popB (pushedB);
3103
3104           accuse = assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3105           assignResultGenerated = TRUE;
3106           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3107         }
3108     }
3109
3110   /* adjust the stack for parameters if required */
3111   if (ic->parmBytes)
3112     {
3113       int i;
3114       if (options.stack10bit) {
3115           if (ic->parmBytes <= 10) {
3116               emitcode(";","stack adjustment for parms");
3117               for (i=0; i < ic->parmBytes ; i++) {
3118                   emitcode("pop","acc");
3119               }
3120           } else {
3121               PROTECT_SP;
3122               emitcode ("clr","c");
3123               emitcode ("mov","a,sp");
3124               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3125               emitcode ("mov","sp,a");
3126               emitcode ("mov","a,esp");
3127               adjustEsp("a");
3128               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3129               emitcode ("mov","esp,a");
3130               UNPROTECT_SP;
3131           }
3132       } else {
3133           if (ic->parmBytes > 3)
3134             {
3135               if (accuse)
3136                 {
3137                   emitcode ("push", "acc");
3138                   accPushed = TRUE;
3139                 }
3140               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3141                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3142                   !assignResultGenerated)
3143                 {
3144                   emitcode ("mov", "F0,c");
3145                   resultInF0 = TRUE;
3146                 }
3147
3148               emitcode ("mov", "a,%s", spname);
3149               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3150               emitcode ("mov", "%s,a", spname);
3151
3152               /* unsaveRegisters from xstack needs acc, but */
3153               /* unsaveRegisters from stack needs this popped */
3154               if (accPushed && !options.useXstack)
3155                 {
3156                   emitcode ("pop", "acc");
3157                   accPushed = FALSE;
3158                 }
3159             }
3160           else
3161               for (i = 0; i < ic->parmBytes; i++)
3162                   emitcode ("dec", "%s", spname);
3163       }
3164   }
3165
3166   /* if we had saved some registers then unsave them */
3167   if (ic->regsSaved && !IFFUNC_CALLEESAVES(dtype))
3168     {
3169       if (accuse && !accPushed && options.useXstack)
3170         {
3171           /* xstack needs acc, but doesn't touch normal stack */
3172           emitcode ("push", "acc");
3173           accPushed = TRUE;
3174         }
3175       unsaveRegisters (ic);
3176     }
3177
3178   /* if register bank was saved then pop them */
3179   if (restoreBank)
3180     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
3181
3182   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) && !assignResultGenerated)
3183     {
3184       if (resultInF0)
3185           emitcode ("mov", "c,F0");
3186
3187       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3188       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3189       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3190     }
3191
3192   if (accPushed)
3193     emitcode ("pop", "acc");
3194 }
3195
3196 /*-----------------------------------------------------------------*/
3197 /* genPcall - generates a call by pointer statement                */
3198 /*-----------------------------------------------------------------*/
3199 static void
3200 genPcall (iCode * ic)
3201 {
3202   sym_link *dtype;
3203   sym_link *etype;
3204   symbol *rlbl = newiTempLabel (NULL);
3205   bool restoreBank=FALSE;
3206   bool resultInF0 = FALSE;
3207
3208   D (emitcode (";", "genPcall"));
3209
3210   dtype = operandType (IC_LEFT (ic))->next;
3211   etype = getSpec(dtype);
3212   /* if caller saves & we have not saved then */
3213   if (!ic->regsSaved)
3214     saveRegisters (ic);
3215
3216   /* if we are calling a not _naked function that is not using
3217      the same register bank then we need to save the
3218      destination registers on the stack */
3219   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
3220       IFFUNC_ISISR (currFunc->type) &&
3221       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
3222     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3223     restoreBank=TRUE;
3224   }
3225
3226   /* push the return address on to the stack */
3227   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
3228   emitcode ("push", "acc");
3229   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
3230   emitcode ("push", "acc");
3231
3232   if (options.model == MODEL_FLAT24)
3233     {
3234       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
3235       emitcode ("push", "acc");
3236     }
3237
3238   /* now push the calling address */
3239   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3240
3241   pushSide (IC_LEFT (ic), FPTRSIZE);
3242
3243   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3244
3245   /* if send set is not empty the assign */
3246   if (_G.sendSet)
3247     {
3248         genSend(reverseSet(_G.sendSet));
3249         _G.sendSet = NULL;
3250     }
3251
3252   /* make the call */
3253   emitcode ("ret", "");
3254   emitLabel (rlbl);
3255
3256
3257   /* if we need assign a result value */
3258   if ((IS_ITEMP (IC_RESULT (ic)) &&
3259        !IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))) &&
3260        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
3261         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
3262       IS_TRUE_SYMOP (IC_RESULT (ic)))
3263     {
3264
3265       _G.accInUse++;
3266       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
3267       _G.accInUse--;
3268
3269       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3270
3271       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3272     }
3273
3274   /* adjust the stack for parameters if required */
3275   if (ic->parmBytes)
3276     {
3277       int i;
3278       if (options.stack10bit) {
3279           if (ic->parmBytes <= 10) {
3280               emitcode(";","stack adjustment for parms");
3281               for (i=0; i < ic->parmBytes ; i++) {
3282                   emitcode("pop","acc");
3283               }
3284           } else {
3285               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3286                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3287                 {
3288                   emitcode ("mov", "F0,c");
3289                   resultInF0 = TRUE;
3290                 }
3291
3292               PROTECT_SP;
3293               emitcode ("clr","c");
3294               emitcode ("mov","a,sp");
3295               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
3296               emitcode ("mov","sp,a");
3297               emitcode ("mov","a,esp");
3298               adjustEsp("a");
3299               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
3300               emitcode ("mov","esp,a");
3301               UNPROTECT_SP;
3302           }
3303       } else {
3304           if (ic->parmBytes > 3) {
3305               if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))) &&
3306                   IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3307                 {
3308                   emitcode ("mov", "F0,c");
3309                   resultInF0 = TRUE;
3310                 }
3311
3312               emitcode ("mov", "a,%s", spname);
3313               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
3314               emitcode ("mov", "%s,a", spname);
3315           }
3316           else
3317               for (i = 0; i < ic->parmBytes; i++)
3318                   emitcode ("dec", "%s", spname);
3319       }
3320     }
3321   /* if register bank was saved then unsave them */
3322   if (restoreBank)
3323     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
3324
3325   /* if we had saved some registers then unsave them */
3326   if (ic->regsSaved)
3327     unsaveRegisters (ic);
3328
3329   if (IS_BIT (OP_SYM_ETYPE (IC_RESULT (ic))))
3330     {
3331       if (resultInF0)
3332           emitcode ("mov", "c,F0");
3333
3334       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
3335       assignResultValue (IC_RESULT (ic), IC_LEFT (ic));
3336       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
3337     }
3338 }
3339
3340 /*-----------------------------------------------------------------*/
3341 /* resultRemat - result  is rematerializable                       */
3342 /*-----------------------------------------------------------------*/
3343 static int
3344 resultRemat (iCode * ic)
3345 {
3346   if (SKIP_IC (ic) || ic->op == IFX)
3347     return 0;
3348
3349   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
3350     {
3351       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
3352       if (sym->remat && !POINTER_SET (ic))
3353         return 1;
3354     }
3355
3356   return 0;
3357 }
3358
3359 /*-----------------------------------------------------------------*/
3360 /* inExcludeList - return 1 if the string is in exclude Reg list   */
3361 /*-----------------------------------------------------------------*/
3362 static int
3363 regsCmp(void *p1, void *p2)
3364 {
3365   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
3366 }
3367
3368 static bool
3369 inExcludeList (char *s)
3370 {
3371   const char *p = setFirstItem(options.excludeRegsSet);
3372
3373   if (p == NULL || STRCASECMP(p, "none") == 0)
3374     return FALSE;
3375
3376
3377   return isinSetWith(options.excludeRegsSet, s, regsCmp);
3378 }
3379
3380 /*-----------------------------------------------------------------*/
3381 /* genFunction - generated code for function entry                 */
3382 /*-----------------------------------------------------------------*/
3383 static void
3384 genFunction (iCode * ic)
3385 {
3386   symbol   *sym = OP_SYMBOL (IC_LEFT (ic));
3387   sym_link *ftype;
3388   bool     switchedPSW = FALSE;
3389   bool     fReentrant = (IFFUNC_ISREENT (sym->type) || options.stackAuto);
3390
3391   D (emitcode (";", "genFunction"));
3392
3393   _G.nRegsSaved = 0;
3394   /* create the function header */
3395   emitcode (";", "-----------------------------------------");
3396   emitcode (";", " function %s", sym->name);
3397   emitcode (";", "-----------------------------------------");
3398
3399   emitcode ("", "%s:", sym->rname);
3400   lineCurr->isLabel = 1;
3401   ftype = operandType (IC_LEFT (ic));
3402   _G.currentFunc = sym;
3403
3404   if (IFFUNC_ISNAKED(ftype))
3405   {
3406       emitcode(";", "naked function: no prologue.");
3407       return;
3408   }
3409
3410   if (options.stack_probe)
3411       emitcode ("lcall","__stack_probe");
3412
3413   /* here we need to generate the equates for the
3414      register bank if required */
3415   if (FUNC_REGBANK (ftype) != rbank)
3416     {
3417       int i;
3418
3419       rbank = FUNC_REGBANK (ftype);
3420       for (i = 0; i < ds390_nRegs; i++)
3421         {
3422           if (regs390[i].print) {
3423               if (strcmp (regs390[i].base, "0") == 0)
3424                   emitcode ("", "%s !equ !constbyte",
3425                             regs390[i].dname,
3426                             8 * rbank + regs390[i].offset);
3427               else
3428                   emitcode ("", "%s !equ %s + !constbyte",
3429                             regs390[i].dname,
3430                             regs390[i].base,
3431                             8 * rbank + regs390[i].offset);
3432           }
3433         }
3434     }
3435
3436   /* if this is an interrupt service routine then
3437      save acc, b, dpl, dph  */
3438   if (IFFUNC_ISISR (sym->type))
3439       { /* is ISR */
3440       if (!inExcludeList ("acc"))
3441         emitcode ("push", "acc");
3442       if (!inExcludeList ("b"))
3443         emitcode ("push", "b");
3444       if (!inExcludeList ("dpl"))
3445         emitcode ("push", "dpl");
3446       if (!inExcludeList ("dph"))
3447         emitcode ("push", "dph");
3448       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3449         {
3450           emitcode ("push", "dpx");
3451           /* Make sure we're using standard DPTR */
3452           emitcode ("push", "dps");
3453           emitcode ("mov", "dps,#0");
3454           if (options.stack10bit)
3455             {
3456               /* This ISR could conceivably use DPTR2. Better save it. */
3457               emitcode ("push", "dpl1");
3458               emitcode ("push", "dph1");
3459               emitcode ("push", "dpx1");
3460               emitcode ("push",  DP2_RESULT_REG);
3461             }
3462         }
3463       /* if this isr has no bank i.e. is going to
3464          run with bank 0 , then we need to save more
3465          registers :-) */
3466       if (!FUNC_REGBANK (sym->type))
3467         {
3468             int i;
3469
3470           /* if this function does not call any other
3471              function then we can be economical and
3472              save only those registers that are used */
3473           if (!IFFUNC_HASFCALL(sym->type))
3474             {
3475               /* if any registers used */
3476               if (sym->regsUsed)
3477                 {
3478                   bool bits_pushed = FALSE;
3479                   /* save the registers used */
3480                   for (i = 0; i < sym->regsUsed->size; i++)
3481                     {
3482                       if (bitVectBitValue (sym->regsUsed, i))
3483                         bits_pushed = pushReg (i, bits_pushed);
3484                     }
3485                 }
3486             }
3487           else
3488             {
3489               /* this function has a function call. We cannot
3490                  determine register usage so we will have to push the
3491                  entire bank */
3492               saveRBank (0, ic, FALSE);
3493               if (options.parms_in_bank1) {
3494                   for (i=0; i < 8 ; i++ ) {
3495                       emitcode ("push","%s",rb1regs[i]);
3496                   }
3497               }
3498             }
3499         }
3500         else
3501         {
3502             /* This ISR uses a non-zero bank.
3503              *
3504              * We assume that the bank is available for our
3505              * exclusive use.
3506              *
3507              * However, if this ISR calls a function which uses some
3508              * other bank, we must save that bank entirely.
3509              */
3510             unsigned long banksToSave = 0;
3511
3512             if (IFFUNC_HASFCALL(sym->type))
3513             {
3514
3515 #define MAX_REGISTER_BANKS 4
3516
3517                 iCode *i;
3518                 int ix;
3519
3520                 for (i = ic; i; i = i->next)
3521                 {
3522                     if (i->op == ENDFUNCTION)
3523                     {
3524                         /* we got to the end OK. */
3525                         break;
3526                     }
3527
3528                     if (i->op == CALL)
3529                     {
3530                         sym_link *dtype;
3531
3532                         dtype = operandType (IC_LEFT(i));
3533                         if (dtype
3534                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3535                         {
3536                              /* Mark this bank for saving. */
3537                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3538                              {
3539                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3540                              }
3541                              else
3542                              {
3543                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3544                              }
3545
3546                              /* And note that we don't need to do it in
3547                               * genCall.
3548                               */
3549                              i->bankSaved = 1;
3550                         }
3551                     }
3552                     if (i->op == PCALL)
3553                     {
3554                         /* This is a mess; we have no idea what
3555                          * register bank the called function might
3556                          * use.
3557                          *
3558                          * The only thing I can think of to do is
3559                          * throw a warning and hope.
3560                          */
3561                         werror(W_FUNCPTR_IN_USING_ISR);
3562                     }
3563                 }
3564
3565                 if (banksToSave && options.useXstack)
3566                 {
3567                     /* Since we aren't passing it an ic,
3568                      * saveRBank will assume r0 is available to abuse.
3569                      *
3570                      * So switch to our (trashable) bank now, so
3571                      * the caller's R0 isn't trashed.
3572                      */
3573                     emitcode ("push", "psw");
3574                     emitcode ("mov", "psw,#!constbyte",
3575                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3576                     switchedPSW = TRUE;
3577                 }
3578
3579                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3580                 {
3581                      if (banksToSave & (1 << ix))
3582                      {
3583                          saveRBank(ix, NULL, FALSE);
3584                      }
3585                 }
3586             }
3587             // TODO: this needs a closer look
3588             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3589         }
3590     }
3591   else
3592     {
3593       /* if callee-save to be used for this function
3594          then save the registers being used in this function */
3595       if (IFFUNC_CALLEESAVES(sym->type))
3596         {
3597           int i;
3598
3599           /* if any registers used */
3600           if (sym->regsUsed)
3601             {
3602               bool bits_pushed = FALSE;
3603               /* save the registers used */
3604               for (i = 0; i < sym->regsUsed->size; i++)
3605                 {
3606                   if (bitVectBitValue (sym->regsUsed, i))
3607                     {
3608                       bits_pushed = pushReg (i, bits_pushed);
3609                       _G.nRegsSaved++;
3610                     }
3611                 }
3612             }
3613         }
3614     }
3615
3616   /* set the register bank to the desired value */
3617   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3618    && !switchedPSW)
3619     {
3620       emitcode ("push", "psw");
3621       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3622     }
3623
3624   if (fReentrant &&
3625        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3626       if (options.stack10bit) {
3627           emitcode ("push","_bpx");
3628           emitcode ("push","_bpx+1");
3629           emitcode ("mov","_bpx,%s",spname);
3630           emitcode ("mov","_bpx+1,esp");
3631           adjustEsp("_bpx+1");
3632       } else {
3633           if (options.useXstack)
3634           {
3635               emitcode ("mov", "r0,%s", spname);
3636               emitcode ("mov", "a,_bp");
3637               emitcode ("movx", "@r0,a");
3638               emitcode ("inc", "%s", spname);
3639           } else {
3640               /* set up the stack */
3641               emitcode ("push", "_bp"); /* save the callers stack  */
3642           }
3643           emitcode ("mov", "_bp,%s", spname);
3644       }
3645   }
3646
3647   /* adjust the stack for the function */
3648   if (sym->stack) {
3649       int i = sym->stack;
3650       if (options.stack10bit) {
3651           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3652           assert (sym->recvSize <= 4);
3653           if (sym->stack <= 8) {
3654               while (i--) emitcode ("push","acc");
3655           } else {
3656               PROTECT_SP;
3657               emitcode ("mov","a,sp");
3658               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3659               emitcode ("mov","sp,a");
3660               emitcode ("mov","a,esp");
3661               adjustEsp("a");
3662               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3663               emitcode ("mov","esp,a");
3664               UNPROTECT_SP;
3665           }
3666       } else {
3667           if (i > 256)
3668               werror (W_STACK_OVERFLOW, sym->name);
3669
3670           if (i > 3 && sym->recvSize < 4) {
3671
3672               emitcode ("mov", "a,sp");
3673               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3674               emitcode ("mov", "sp,a");
3675
3676           } else
3677               while (i--)
3678                   emitcode ("inc", "sp");
3679       }
3680   }
3681
3682   if (sym->xstack)
3683     {
3684
3685       emitcode ("mov", "a,_spx");
3686       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3687       emitcode ("mov", "_spx,a");
3688     }
3689
3690   /* if critical function then turn interrupts off */
3691   if (IFFUNC_ISCRITICAL (ftype))
3692     {
3693       symbol *tlbl = newiTempLabel (NULL);
3694       emitcode ("setb", "c");
3695       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3696       emitcode ("clr", "c");
3697       emitLabel (tlbl);
3698       emitcode ("push", "psw"); /* save old ea via c in psw */
3699     }
3700 }
3701
3702 /*-----------------------------------------------------------------*/
3703 /* genEndFunction - generates epilogue for functions               */
3704 /*-----------------------------------------------------------------*/
3705 static void
3706 genEndFunction (iCode * ic)
3707 {
3708   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3709   lineNode *lnp = lineCurr;
3710   bitVect *regsUsed;
3711   bitVect *regsUsedPrologue;
3712   bitVect *regsUnneeded;
3713   int idx;
3714
3715   D (emitcode (";", "genEndFunction"));
3716
3717   _G.currentFunc = NULL;
3718   if (IFFUNC_ISNAKED(sym->type))
3719   {
3720       emitcode(";", "naked function: no epilogue.");
3721       if (options.debug && currFunc)
3722         debugFile->writeEndFunction (currFunc, ic, 0);
3723       return;
3724   }
3725
3726   if (IFFUNC_ISCRITICAL (sym->type))
3727     {
3728       if (IS_BIT (OP_SYM_ETYPE (IC_LEFT (ic))))
3729         {
3730           emitcode ("rlc", "a");   /* save c in a */
3731           emitcode ("pop", "psw"); /* restore ea via c in psw */
3732           emitcode ("mov", "ea,c");
3733           emitcode ("rrc", "a");   /* restore c from a */
3734         }
3735       else
3736         {
3737           emitcode ("pop", "psw"); /* restore ea via c in psw */
3738           emitcode ("mov", "ea,c");
3739         }
3740     }
3741
3742   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3743        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3744
3745       if (options.stack10bit) {
3746           PROTECT_SP;
3747           emitcode ("mov", "sp,_bpx", spname);
3748           emitcode ("mov", "esp,_bpx+1", spname);
3749           UNPROTECT_SP;
3750       } else {
3751           emitcode ("mov", "%s,_bp", spname);
3752       }
3753   }
3754
3755   /* if use external stack but some variables were
3756      added to the local stack then decrement the
3757      local stack */
3758   if (options.useXstack && sym->stack) {
3759       emitcode ("mov", "a,sp");
3760       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3761       emitcode ("mov", "sp,a");
3762   }
3763
3764
3765   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3766        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3767
3768       if (options.useXstack) {
3769           emitcode ("mov", "r0,%s", spname);
3770           emitcode ("movx", "a,@r0");
3771           emitcode ("mov", "_bp,a");
3772           emitcode ("dec", "%s", spname);
3773       } else {
3774           if (options.stack10bit) {
3775               emitcode ("pop", "_bpx+1");
3776               emitcode ("pop", "_bpx");
3777           } else {
3778               emitcode ("pop", "_bp");
3779           }
3780       }
3781   }
3782
3783   /* restore the register bank  */
3784   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3785   {
3786     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3787      || !options.useXstack)
3788     {
3789         /* Special case of ISR using non-zero bank with useXstack
3790          * is handled below.
3791          */
3792         emitcode ("pop", "psw");
3793     }
3794   }
3795
3796   if (IFFUNC_ISISR (sym->type))
3797     { /* is ISR */
3798
3799       /* now we need to restore the registers */
3800       /* if this isr has no bank i.e. is going to
3801          run with bank 0 , then we need to save more
3802          registers :-) */
3803       if (!FUNC_REGBANK (sym->type))
3804         {
3805           int i;
3806           /* if this function does not call any other
3807              function then we can be economical and
3808              save only those registers that are used */
3809           if (!IFFUNC_HASFCALL(sym->type))
3810             {
3811               /* if any registers used */
3812               if (sym->regsUsed)
3813                 {
3814                   bool bits_popped = FALSE;
3815                   /* save the registers used */
3816                   for (i = sym->regsUsed->size; i >= 0; i--)
3817                     {
3818                       if (bitVectBitValue (sym->regsUsed, i))
3819                         bits_popped = popReg (i, bits_popped);
3820                     }
3821                 }
3822             }
3823           else
3824             {
3825               /* this function has a function call. We cannot
3826                  determine register usage so we will have to pop the
3827                  entire bank */
3828               if (options.parms_in_bank1) {
3829                   for (i = 7 ; i >= 0 ; i-- ) {
3830                       emitcode ("pop","%s",rb1regs[i]);
3831                   }
3832               }
3833               unsaveRBank (0, ic, FALSE);
3834             }
3835         }
3836       else
3837         {
3838             /* This ISR uses a non-zero bank.
3839              *
3840              * Restore any register banks saved by genFunction
3841              * in reverse order.
3842              */
3843             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3844             int ix;
3845
3846             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3847             {
3848                 if (savedBanks & (1 << ix))
3849                 {
3850                     unsaveRBank(ix, NULL, FALSE);
3851                 }
3852             }
3853
3854             if (options.useXstack)
3855             {
3856                 /* Restore bank AFTER calling unsaveRBank,
3857                  * since it can trash r0.
3858                  */
3859                 emitcode ("pop", "psw");
3860             }
3861         }
3862
3863       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3864         {
3865           if (options.stack10bit)
3866             {
3867               emitcode ("pop", DP2_RESULT_REG);
3868               emitcode ("pop", "dpx1");
3869               emitcode ("pop", "dph1");
3870               emitcode ("pop", "dpl1");
3871             }
3872           emitcode ("pop", "dps");
3873           emitcode ("pop", "dpx");
3874         }
3875       if (!inExcludeList ("dph"))
3876         emitcode ("pop", "dph");
3877       if (!inExcludeList ("dpl"))
3878         emitcode ("pop", "dpl");
3879       if (!inExcludeList ("b"))
3880         emitcode ("pop", "b");
3881       if (!inExcludeList ("acc"))
3882         emitcode ("pop", "acc");
3883
3884       /* if debug then send end of function */
3885       if (options.debug && currFunc)
3886         {
3887           debugFile->writeEndFunction (currFunc, ic, 1);
3888         }
3889
3890       emitcode ("reti", "");
3891     }
3892   else
3893     {
3894       if (IFFUNC_CALLEESAVES(sym->type))
3895         {
3896           int i;
3897
3898           /* if any registers used */
3899           if (sym->regsUsed)
3900             {
3901               /* save the registers used */
3902               for (i = sym->regsUsed->size; i >= 0; i--)
3903                 {
3904                   if (bitVectBitValue (sym->regsUsed, i))
3905                     emitcode ("pop", "%s", REG_WITH_INDEX (i)->dname);
3906                 }
3907             }
3908         }
3909
3910       /* if debug then send end of function */
3911       if (options.debug && currFunc)
3912         {
3913           debugFile->writeEndFunction (currFunc, ic, 1);
3914         }
3915
3916       emitcode ("ret", "");
3917     }
3918
3919   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3920     return;
3921
3922   /* If this was an interrupt handler using bank 0 that called another */
3923   /* function, then all registers must be saved; nothing to optimized. */
3924   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3925       && !FUNC_REGBANK(sym->type))
3926     return;
3927
3928   /* There are no push/pops to optimize if not callee-saves or ISR */
3929   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3930     return;
3931
3932   /* If there were stack parameters, we cannot optimize without also    */
3933   /* fixing all of the stack offsets; this is too dificult to consider. */
3934   if (FUNC_HASSTACKPARM(sym->type))
3935     return;
3936
3937   /* Compute the registers actually used */
3938   regsUsed = newBitVect (ds390_nRegs);
3939   regsUsedPrologue = newBitVect (ds390_nRegs);
3940   while (lnp)
3941     {
3942       if (lnp->ic && lnp->ic->op == FUNCTION)
3943         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3944       else
3945         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3946
3947       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3948           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3949         break;
3950       if (!lnp->prev)
3951         break;
3952       lnp = lnp->prev;
3953     }
3954
3955   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3956       && !bitVectBitValue (regsUsed, DPS_IDX))
3957     {
3958       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3959     }
3960
3961   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3962       && !bitVectBitValue (regsUsed, CND_IDX))
3963     {
3964       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3965       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3966           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3967         bitVectUnSetBit (regsUsed, CND_IDX);
3968     }
3969   else
3970     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3971
3972   /* If this was an interrupt handler that called another function */
3973   /* function, then assume working registers may be modified by it. */
3974   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3975     {
3976       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3977       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3978       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3979       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3980       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3981       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3982       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3983       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3984       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3985       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3986       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3987     }
3988
3989   /* Remove the unneeded push/pops */
3990   regsUnneeded = newBitVect (ds390_nRegs);
3991   while (lnp)
3992     {
3993       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3994         {
3995           if (!strncmp(lnp->line, "push", 4))
3996             {
3997               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3998               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3999                 {
4000                   connectLine (lnp->prev, lnp->next);
4001                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4002                 }
4003             }
4004           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
4005             {
4006               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
4007               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
4008                 {
4009                   connectLine (lnp->prev, lnp->next);
4010                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
4011                 }
4012             }
4013         }
4014       lnp = lnp->next;
4015     }
4016
4017   for (idx = 0; idx < regsUnneeded->size; idx++)
4018     if (bitVectBitValue (regsUnneeded, idx))
4019       emitcode (";", "eliminated unneeded push/pop %s", REG_WITH_INDEX (idx)->dname);
4020
4021   freeBitVect (regsUnneeded);
4022   freeBitVect (regsUsed);
4023   freeBitVect (regsUsedPrologue);
4024 }
4025
4026 /*-----------------------------------------------------------------*/
4027 /* genJavaNativeRet - generate code for return JavaNative          */
4028 /*-----------------------------------------------------------------*/
4029 static void genJavaNativeRet(iCode *ic)
4030 {
4031     int i, size;
4032
4033     aopOp (IC_LEFT (ic), ic, FALSE,
4034            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
4035     size = AOP_SIZE (IC_LEFT (ic));
4036
4037     assert (size <= 4);
4038
4039     /* it is assigned to GPR0-R3 then push them */
4040     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
4041         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
4042         for (i = 0 ; i < size ; i++ ) {
4043             emitcode ("push","%s",
4044                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4045         }
4046         for (i = (size-1) ; i >= 0 ; i--) {
4047             emitcode ("pop","a%s",javaRet[i]);
4048         }
4049     } else {
4050         for (i = 0 ; i < size ; i++)
4051             emitcode ("mov","%s,%s",javaRet[i],
4052                       aopGet(IC_LEFT(ic),i,FALSE,TRUE,DP2_RESULT_REG));
4053     }
4054     for (i = size ; i < 4 ; i++ )
4055             emitcode ("mov","%s,#0",javaRet[i]);
4056     return;
4057 }
4058
4059 /*-----------------------------------------------------------------*/
4060 /* genRet - generate code for return statement                     */
4061 /*-----------------------------------------------------------------*/
4062 static void
4063 genRet (iCode * ic)
4064 {
4065   int size, offset = 0, pushed = 0;
4066
4067   D (emitcode (";", "genRet"));
4068
4069   /* if we have no return value then
4070      just generate the "ret" */
4071   if (!IC_LEFT (ic))
4072     goto jumpret;
4073
4074   /* if this is a JavaNative function then return
4075      value in different register */
4076   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
4077       genJavaNativeRet(ic);
4078       goto jumpret;
4079   }
4080   /* we have something to return then
4081      move the return value into place */
4082   aopOp (IC_LEFT (ic), ic, FALSE,
4083          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
4084   size = AOP_SIZE (IC_LEFT (ic));
4085
4086   _startLazyDPSEvaluation ();
4087
4088   if (IS_BIT(_G.currentFunc->etype))
4089     {
4090       movc (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4091       size = 0;
4092     }
4093
4094   while (size--)
4095     {
4096       char *l;
4097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
4098         {
4099           l = aopGet (IC_LEFT (ic), offset++,
4100                       FALSE, TRUE, NULL);
4101           emitcode ("push", "%s", l);
4102           pushed++;
4103         }
4104       else
4105         {
4106           /* Since A is the last element of fReturn,
4107            * it is OK to clobber it in the aopGet.
4108            */
4109           l = aopGet (IC_LEFT (ic), offset,
4110                       FALSE, FALSE, NULL);
4111           if (strcmp (fReturn[offset], l))
4112             emitcode ("mov", "%s,%s", fReturn[offset++], l);
4113         }
4114     }
4115   _endLazyDPSEvaluation ();
4116
4117   while (pushed)
4118     {
4119       pushed--;
4120       if (strcmp (fReturn[pushed], "a"))
4121         emitcode ("pop", fReturn[pushed]);
4122       else
4123         emitcode ("pop", "acc");
4124     }
4125   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
4126
4127 jumpret:
4128   /* generate a jump to the return label
4129      if the next is not the return statement */
4130   if (!(ic->next && ic->next->op == LABEL &&
4131         IC_LABEL (ic->next) == returnLabel))
4132
4133     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
4134
4135 }
4136
4137 /*-----------------------------------------------------------------*/
4138 /* genLabel - generates a label                                    */
4139 /*-----------------------------------------------------------------*/
4140 static void
4141 genLabel (iCode * ic)
4142 {
4143   /* special case never generate */
4144   if (IC_LABEL (ic) == entryLabel)
4145     return;
4146
4147   D (emitcode (";", "genLabel"));
4148
4149   emitLabel (IC_LABEL (ic));
4150 }
4151
4152 /*-----------------------------------------------------------------*/
4153 /* genGoto - generates a ljmp                                      */
4154 /*-----------------------------------------------------------------*/
4155 static void
4156 genGoto (iCode * ic)
4157 {
4158   D (emitcode (";", "genGoto"));
4159
4160   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
4161 }
4162
4163 /*-----------------------------------------------------------------*/
4164 /* findLabelBackwards: walks back through the iCode chain looking  */
4165 /* for the given label. Returns number of iCode instructions     */
4166 /* between that label and given ic.          */
4167 /* Returns zero if label not found.          */
4168 /*-----------------------------------------------------------------*/
4169 static int
4170 findLabelBackwards (iCode * ic, int key)
4171 {
4172   int count = 0;
4173
4174   while (ic->prev)
4175     {
4176       ic = ic->prev;
4177       count++;
4178
4179       /* If we have any pushes or pops, we cannot predict the distance.
4180          I don't like this at all, this should be dealt with in the
4181          back-end */
4182       if (ic->op == IPUSH || ic->op == IPOP) {
4183         return 0;
4184       }
4185
4186       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
4187         {
4188           /* printf("findLabelBackwards = %d\n", count); */
4189           return count;
4190         }
4191     }
4192
4193   return 0;
4194 }
4195
4196 /*-----------------------------------------------------------------*/
4197 /* genPlusIncr :- does addition with increment if possible         */
4198 /*-----------------------------------------------------------------*/
4199 static bool
4200 genPlusIncr (iCode * ic)
4201 {
4202   unsigned int icount;
4203   unsigned int size = getDataSize (IC_RESULT (ic));
4204
4205   /* will try to generate an increment */
4206   /* if the right side is not a literal
4207      we cannot */
4208   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4209     return FALSE;
4210
4211   /* if the literal value of the right hand side
4212      is greater than 4 then it is not worth it */
4213   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4214     return FALSE;
4215
4216   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4217       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4218       while (icount--) {
4219           emitcode("inc","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4220       }
4221       return TRUE;
4222   }
4223   /* if increment 16 bits in register */
4224   if (
4225        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4226        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4227        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4228        (size > 1) &&
4229        (icount == 1))
4230     {
4231       symbol  *tlbl;
4232       int     emitTlbl;
4233       int     labelRange;
4234       char    *l;
4235
4236       /* If the next instruction is a goto and the goto target
4237        * is <= 5 instructions previous to this, we can generate
4238        * jumps straight to that target.
4239        */
4240       if (ic->next && ic->next->op == GOTO
4241           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4242           && labelRange <= 5)
4243         {
4244           D (emitcode (";", "tail increment optimized (range %d)", labelRange));
4245           tlbl = IC_LABEL (ic->next);
4246           emitTlbl = 0;
4247         }
4248       else
4249         {
4250           tlbl = newiTempLabel (NULL);
4251           emitTlbl = 1;
4252         }
4253       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4254       emitcode ("inc", "%s", l);
4255
4256       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4257           IS_AOP_PREG (IC_RESULT (ic)))
4258         {
4259           emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4260         }
4261       else
4262         {
4263           emitcode ("clr", "a");
4264           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4265         }
4266
4267       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4268       emitcode ("inc", "%s", l);
4269       if (size > 2)
4270         {
4271           if (!strcmp(l, "acc"))
4272             {
4273                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4274             }
4275           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4276                    IS_AOP_PREG (IC_RESULT (ic)))
4277             {
4278                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4279             }
4280           else
4281             {
4282                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4283             }
4284
4285           l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4286           emitcode ("inc", "%s", l);
4287         }
4288       if (size > 3)
4289         {
4290           if (!strcmp(l, "acc"))
4291             {
4292                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4293             }
4294           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4295                    IS_AOP_PREG (IC_RESULT (ic)))
4296             {
4297                 emitcode ("cjne", "%s,%s,!tlabel", l, zero, tlbl->key + 100);
4298             }
4299           else
4300             {
4301                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4302             }
4303
4304           l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4305           emitcode ("inc", "%s", l);
4306         }
4307
4308       if (emitTlbl)
4309         {
4310           emitLabel (tlbl);
4311         }
4312       return TRUE;
4313     }
4314
4315   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
4316       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
4317       options.model == MODEL_FLAT24 )
4318     {
4319       if (IC_RESULT(ic)->isGptr)
4320         {
4321           emitcode ("mov", "b,%s", aopGet(IC_LEFT (ic), 3, FALSE, FALSE, NULL));
4322         }
4323       switch (size) {
4324       case 3:
4325           emitcode ("mov", "dpx,%s", aopGet(IC_LEFT (ic), 2, FALSE, FALSE, NULL));
4326       case 2:
4327           emitcode ("mov", "dph,%s", aopGet(IC_LEFT (ic), 1, FALSE, FALSE, NULL));
4328       case 1:
4329           emitcode ("mov", "dpl,%s", aopGet(IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4330           break;
4331       }
4332       while (icount--)
4333         emitcode ("inc", "dptr");
4334       return TRUE;
4335   }
4336
4337   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
4338       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
4339       icount <= 5 ) {
4340       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
4341       while (icount--)
4342         emitcode ("inc", "dptr");
4343       emitcode ("mov", "dps,#0");
4344       return TRUE;
4345   }
4346
4347   /* if the sizes are greater than 1 then we cannot */
4348   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4349       AOP_SIZE (IC_LEFT (ic)) > 1)
4350     return FALSE;
4351
4352   /* we can if the aops of the left & result match or
4353      if they are in registers and the registers are the
4354      same */
4355   if (
4356        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4357        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4358        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4359     {
4360       if (icount > 3)
4361         {
4362           MOVA (aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4363           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
4364           aopPut (IC_RESULT (ic), "a", 0);
4365         }
4366       else
4367         {
4368           _startLazyDPSEvaluation ();
4369           while (icount--)
4370             {
4371               emitcode ("inc", "%s", aopGet (IC_LEFT (ic), 0, FALSE, FALSE, NULL));
4372             }
4373           _endLazyDPSEvaluation ();
4374         }
4375
4376       return TRUE;
4377     }
4378
4379   return FALSE;
4380 }
4381
4382 /*-----------------------------------------------------------------*/
4383 /* outBitAcc - output a bit in acc                                 */
4384 /*-----------------------------------------------------------------*/
4385 static void
4386 outBitAcc (operand * result)
4387 {
4388   symbol *tlbl = newiTempLabel (NULL);
4389   /* if the result is a bit */
4390   if (AOP_TYPE (result) == AOP_CRY)
4391     {
4392       aopPut (result, "a", 0);
4393     }
4394   else
4395     {
4396       emitcode ("jz", "!tlabel", tlbl->key + 100);
4397       emitcode ("mov", "a,%s", one);
4398       emitLabel (tlbl);
4399       outAcc (result);
4400     }
4401 }
4402
4403 /*-----------------------------------------------------------------*/
4404 /* genPlusBits - generates code for addition of two bits           */
4405 /*-----------------------------------------------------------------*/
4406 static void
4407 genPlusBits (iCode * ic)
4408 {
4409   D (emitcode (";", "genPlusBits"));
4410
4411   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4412     {
4413       symbol *lbl = newiTempLabel (NULL);
4414       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4415       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4416       emitcode ("cpl", "c");
4417       emitLabel (lbl);
4418       outBitC (IC_RESULT (ic));
4419     }
4420   else
4421     {
4422       emitcode ("clr", "a");
4423       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4424       emitcode ("rlc", "a");
4425       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4426       emitcode ("addc", "a,%s", zero);
4427       outAcc (IC_RESULT (ic));
4428     }
4429 }
4430
4431 static void
4432 adjustArithmeticResult (iCode * ic)
4433 {
4434   if (opIsGptr (IC_RESULT (ic)) &&
4435       opIsGptr (IC_LEFT (ic)) &&
4436       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
4437     {
4438       aopPut (IC_RESULT (ic),
4439               aopGet (IC_LEFT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4440               GPTRSIZE - 1);
4441     }
4442
4443   if (opIsGptr (IC_RESULT (ic)) &&
4444       opIsGptr (IC_RIGHT (ic)) &&
4445       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4446     {
4447       aopPut (IC_RESULT (ic),
4448               aopGet (IC_RIGHT (ic), GPTRSIZE - 1, FALSE, FALSE, NULL),
4449               GPTRSIZE - 1);
4450     }
4451
4452   if (opIsGptr (IC_RESULT (ic)) &&
4453       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
4454       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
4455       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
4456       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
4457     {
4458       char buffer[5];
4459       SNPRINTF (buffer, sizeof(buffer),
4460                 "#%d", pointerTypeToGPByte (pointerCode (getSpec (operandType (IC_LEFT (ic)))), NULL, NULL));
4461       aopPut (IC_RESULT (ic), buffer, GPTRSIZE - 1);
4462     }
4463 }
4464
4465 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
4466 // generates the result if possible. If result is generated, returns TRUE; otherwise
4467 // returns false and caller must deal with fact that result isn't aopOp'd.
4468 bool aopOp3(iCode * ic)
4469 {
4470     bool dp1InUse, dp2InUse;
4471     bool useDp2;
4472
4473     // First, generate the right opcode. DPTR may be used if neither left nor result are
4474     // of type AOP_STR.
4475
4476 //    D (emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4477 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4478 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4479 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4480 //      );
4481 //    D (emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4482 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4483 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4484 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4485 //      );
4486
4487     // Right uses DPTR unless left or result is an AOP_STR; however,
4488     // if right is an AOP_STR, it must use DPTR regardless.
4489     if ((AOP_IS_STR (IC_LEFT (ic)) || AOP_IS_STR (IC_RESULT (ic)))
4490      && !AOP_IS_STR (IC_RIGHT (ic)))
4491     {
4492         useDp2 = TRUE;
4493     }
4494     else
4495     {
4496         useDp2 = FALSE;
4497     }
4498
4499     aopOp (IC_RIGHT(ic), ic, FALSE, useDp2);
4500
4501     // if the right used DPTR, left MUST use DPTR2.
4502     // if the right used DPTR2, left MUST use DPTR.
4503     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4504     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4505     // enabling us to assign DPTR to result.
4506
4507     if (AOP_USESDPTR (IC_RIGHT (ic)))
4508     {
4509         useDp2 = TRUE;
4510     }
4511     else if (AOP_USESDPTR2 (IC_RIGHT (ic)))
4512     {
4513         useDp2 = FALSE;
4514     }
4515     else
4516     {
4517         if (AOP_IS_STR (IC_RESULT (ic)) && !AOP_IS_STR (IC_LEFT (ic)))
4518         {
4519             useDp2 = TRUE;
4520         }
4521         else
4522         {
4523             useDp2 = FALSE;
4524         }
4525     }
4526
4527     aopOp (IC_LEFT (ic), ic, FALSE, useDp2);
4528
4529
4530     // We've op'd the left & right. So, if left or right are the same operand as result,
4531     // we know aopOp will succeed, and we can just do it & bail.
4532     if (isOperandEqual (IC_LEFT (ic), IC_RESULT (ic)))
4533       {
4534         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4535         return TRUE;
4536       }
4537     if (isOperandEqual (IC_RIGHT (ic), IC_RESULT (ic)))
4538       {
4539 //      D (emitcode(";", "aopOp3: (left | right) & result equal"));
4540         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4541         return TRUE;
4542       }
4543
4544     // Operands may be equivalent (but not equal) if they share a spill location. If
4545     // so, use the same DPTR or DPTR2.
4546     if (operandsEqu (IC_LEFT (ic), IC_RESULT (ic)))
4547       {
4548         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4549         return TRUE;
4550       }
4551     if (operandsEqu (IC_RIGHT (ic), IC_RESULT (ic)))
4552       {
4553         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4554         return TRUE;
4555       }
4556
4557     // Note which dptrs are currently in use.
4558     dp1InUse = AOP_USESDPTR (IC_LEFT (ic)) || AOP_USESDPTR (IC_RIGHT (ic));
4559     dp2InUse = AOP_USESDPTR2 (IC_LEFT (ic)) || AOP_USESDPTR2 (IC_RIGHT (ic));
4560
4561     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4562     // generate it.
4563     if (dp1InUse && AOP_IS_STR (IC_RESULT (ic)))
4564     {
4565         return FALSE;
4566     }
4567
4568     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4569     if (dp2InUse && AOP_IS_DPTRn (IC_RESULT (ic)))
4570     {
4571         return FALSE;
4572     }
4573
4574     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4575     if (dp1InUse && dp2InUse && isOperandInFarSpace (IC_RESULT (ic)))
4576     {
4577         return FALSE;
4578     }
4579
4580     aopOp (IC_RESULT (ic), ic, TRUE, dp1InUse);
4581
4582     // Some sanity checking...
4583     if (dp1InUse && AOP_USESDPTR (IC_RESULT (ic)))
4584     {
4585         fprintf(stderr,
4586                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4587                 __FILE__, __LINE__, ic->filename, ic->lineno);
4588         emitcode(";", ">>> unexpected DPTR here.");
4589     }
4590
4591     if (dp2InUse && AOP_USESDPTR2 (IC_RESULT (ic)))
4592     {
4593         fprintf(stderr,
4594                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4595                 __FILE__, __LINE__, ic->filename, ic->lineno);
4596         emitcode(";", ">>> unexpected DPTR2 here.");
4597     }
4598
4599     return TRUE;
4600 }
4601
4602 // Macro to aopOp all three operands of an ic. If this cannot be done,
4603 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4604 // will be set TRUE. The caller must then handle the case specially, noting
4605 // that the IC_RESULT operand is not aopOp'd.
4606 //
4607 #define AOP_OP_3_NOFATAL(ic, rc) \
4608             do { rc = !aopOp3(ic); } while (0)
4609
4610 // aopOp the left & right operands of an ic.
4611 #define AOP_OP_2(ic) \
4612     aopOp (IC_RIGHT (ic), ic, FALSE, AOP_IS_STR (IC_LEFT (ic))); \
4613     aopOp (IC_LEFT (ic), ic, FALSE, AOP_USESDPTR (IC_RIGHT (ic)));
4614
4615 // convienience macro.
4616 #define AOP_SET_LOCALS(ic) \
4617     left = IC_LEFT(ic); \
4618     right = IC_RIGHT(ic); \
4619     result = IC_RESULT(ic);
4620
4621
4622 // Given an integer value of pushedSize bytes on the stack,
4623 // adjust it to be resultSize bytes, either by discarding
4624 // the most significant bytes or by zero-padding.
4625 //
4626 // On exit from this macro, pushedSize will have been adjusted to
4627 // equal resultSize, and ACC may be trashed.
4628 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4629       /* If the pushed data is bigger than the result,          \
4630        * simply discard unused bytes. Icky, but works.          \
4631        */                                                       \
4632       while (pushedSize > resultSize)                           \
4633       {                                                         \
4634           D (emitcode (";", "discarding unused result byte.")); \
4635           emitcode ("pop", "acc");                              \
4636           pushedSize--;                                         \
4637       }                                                         \
4638       if (pushedSize < resultSize)                              \
4639       {                                                         \
4640           emitcode ("clr", "a");                                \
4641           /* Conversly, we haven't pushed enough here.          \
4642            * just zero-pad, and all is well.                    \
4643            */                                                   \
4644           while (pushedSize < resultSize)                       \
4645           {                                                     \
4646               emitcode("push", "acc");                          \
4647               pushedSize++;                                     \
4648           }                                                     \
4649       }                                                         \
4650       assert(pushedSize == resultSize);
4651
4652 /*-----------------------------------------------------------------*/
4653 /* genPlus - generates code for addition                           */
4654 /*-----------------------------------------------------------------*/
4655 static void
4656 genPlus (iCode * ic)
4657 {
4658   int size, offset = 0;
4659   bool pushResult;
4660   int rSize;
4661   bool swappedLR = FALSE;
4662
4663   D (emitcode (";", "genPlus"));
4664
4665   /* special cases :- */
4666   if ( AOP_IS_STR (IC_LEFT (ic)) &&
4667       isOperandLiteral (IC_RIGHT (ic)) && OP_SYMBOL (IC_RESULT (ic))->ruonly) {
4668       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4669       size = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4670       if (size <= 9) {
4671           while (size--) emitcode ("inc","dptr");
4672       } else {
4673           emitcode ("mov", "a,dpl");
4674           emitcode ("add", "a,#!constbyte", size & 0xff);
4675           emitcode ("mov", "dpl,a");
4676           emitcode ("mov", "a,dph");
4677           emitcode ("addc", "a,#!constbyte", (size >> 8) & 0xff);
4678           emitcode ("mov", "dph,a");
4679           emitcode ("mov", "a,dpx");
4680           emitcode ("addc", "a,#!constbyte", (size >> 16) & 0xff);
4681           emitcode ("mov", "dpx,a");
4682       }
4683       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4684       return ;
4685   }
4686   if ( IS_SYMOP (IC_LEFT (ic)) &&
4687        OP_SYMBOL (IC_LEFT (ic))->remat &&
4688        isOperandInFarSpace (IC_RIGHT (ic))) {
4689       operand *op = IC_RIGHT(ic);
4690       IC_RIGHT(ic) = IC_LEFT(ic);
4691       IC_LEFT(ic) = op;
4692   }
4693
4694   AOP_OP_3_NOFATAL (ic, pushResult);
4695
4696   if (pushResult)
4697     {
4698       D (emitcode (";", "genPlus: must push result: 3 ops in far space"));
4699     }
4700
4701   if (!pushResult)
4702     {
4703       /* if literal, literal on the right or
4704          if left requires ACC or right is already
4705          in ACC */
4706       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
4707           ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic)))) ||
4708           AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4709         {
4710           operand *t = IC_RIGHT (ic);
4711           IC_RIGHT (ic) = IC_LEFT (ic);
4712           IC_LEFT (ic) = t;
4713           swappedLR = TRUE;
4714           D (emitcode (";", "Swapped plus args."));
4715         }
4716
4717       /* if both left & right are in bit
4718          space */
4719       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4720           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4721         {
4722           genPlusBits (ic);
4723           goto release;
4724         }
4725
4726       /* if left in bit space & right literal */
4727       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4728           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4729         {
4730           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4731           /* if result in bit space */
4732           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4733             {
4734               if (ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4735                 emitcode ("cpl", "c");
4736               outBitC (IC_RESULT (ic));
4737             }
4738           else
4739             {
4740               size = getDataSize (IC_RESULT (ic));
4741               _startLazyDPSEvaluation ();
4742               while (size--)
4743                 {
4744                   MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4745                   emitcode ("addc", "a,%s", zero);
4746                   aopPut (IC_RESULT (ic), "a", offset++);
4747                 }
4748               _endLazyDPSEvaluation ();
4749             }
4750           goto release;
4751         }
4752
4753       /* if I can do an increment instead
4754          of add then GOOD for ME */
4755       if (genPlusIncr (ic) == TRUE)
4756         {
4757           D (emitcode (";", "did genPlusIncr"));
4758           goto release;
4759         }
4760
4761     }
4762   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4763
4764   _startLazyDPSEvaluation ();
4765   while (size--)
4766     {
4767       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4768         {
4769           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
4770           if (offset == 0)
4771             emitcode ("add", "a,%s",
4772                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4773           else
4774             emitcode ("addc", "a,%s",
4775                  aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4776         }
4777       else
4778         {
4779           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4780           {
4781               /* right is going to use ACC or we would have taken the
4782                * above branch.
4783                */
4784               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4785               TR_AP("#3");
4786               D(emitcode(";", "+ AOP_ACC special case."););
4787               emitcode("xch", "a, %s", DP2_RESULT_REG);
4788           }
4789           MOVA (aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
4790           if (offset == 0)
4791           {
4792             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4793             {
4794                 TR_AP("#4");
4795                 emitcode("add", "a, %s", DP2_RESULT_REG);
4796             }
4797             else
4798             {
4799                 emitcode ("add", "a,%s",
4800                           aopGet (IC_LEFT(ic), offset, FALSE, FALSE,
4801                                   DP2_RESULT_REG));
4802             }
4803           }
4804           else
4805           {
4806             emitcode ("addc", "a,%s",
4807                   aopGet (IC_LEFT (ic), offset, FALSE, FALSE,
4808                           DP2_RESULT_REG));
4809           }
4810         }
4811       if (!pushResult)
4812         {
4813           aopPut (IC_RESULT (ic), "a", offset);
4814         }
4815       else
4816         {
4817           emitcode ("push", "acc");
4818         }
4819       offset++;
4820     }
4821   _endLazyDPSEvaluation ();
4822
4823   if (pushResult)
4824     {
4825       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4826
4827       size = getDataSize (IC_LEFT (ic));
4828       rSize = getDataSize (IC_RESULT (ic));
4829
4830       ADJUST_PUSHED_RESULT(size, rSize);
4831
4832       _startLazyDPSEvaluation ();
4833       while (size--)
4834         {
4835           emitcode ("pop", "acc");
4836           aopPut (IC_RESULT (ic), "a", size);
4837         }
4838       _endLazyDPSEvaluation ();
4839     }
4840
4841   adjustArithmeticResult (ic);
4842
4843 release:
4844   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4845   if (!swappedLR)
4846     {
4847       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4848       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4849     }
4850   else
4851     {
4852       freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4853       freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4854     }
4855 }
4856
4857 /*-----------------------------------------------------------------*/
4858 /* genMinusDec :- does subtraction with decrement if possible      */
4859 /*-----------------------------------------------------------------*/
4860 static bool
4861 genMinusDec (iCode * ic)
4862 {
4863   unsigned int icount;
4864   unsigned int size = getDataSize (IC_RESULT (ic));
4865
4866   /* will try to generate an increment */
4867   /* if the right side is not a literal
4868      we cannot */
4869   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4870     return FALSE;
4871
4872   /* if the literal value of the right hand side
4873      is greater than 4 then it is not worth it */
4874   if ((icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4875     return FALSE;
4876
4877   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4878       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4879       while (icount--) {
4880           emitcode("dec","%s",aopGet(IC_RESULT(ic),0,FALSE,FALSE,NULL));
4881       }
4882       return TRUE;
4883   }
4884   /* if decrement 16 bits in register */
4885   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4886       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4887       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4888       (size > 1) &&
4889       (icount == 1))
4890     {
4891       symbol *tlbl;
4892       int    emitTlbl;
4893       int    labelRange;
4894       char   *l;
4895
4896       /* If the next instruction is a goto and the goto target
4897          * is <= 5 instructions previous to this, we can generate
4898          * jumps straight to that target.
4899        */
4900       if (ic->next && ic->next->op == GOTO
4901           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4902           && labelRange <= 5)
4903         {
4904           D (emitcode (";", "tail decrement optimized (range %d)", labelRange));
4905           tlbl = IC_LABEL (ic->next);
4906           emitTlbl = 0;
4907         }
4908       else
4909         {
4910           tlbl = newiTempLabel (NULL);
4911           emitTlbl = 1;
4912         }
4913
4914       l = aopGet (IC_RESULT (ic), LSB, FALSE, FALSE, NULL);
4915       emitcode ("dec", "%s", l);
4916
4917       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4918           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4919           IS_AOP_PREG (IC_RESULT (ic)))
4920       {
4921           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4922       }
4923       else
4924       {
4925           emitcode ("mov", "a,#!constbyte",0xff);
4926           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4927       }
4928       l = aopGet (IC_RESULT (ic), MSB16, FALSE, FALSE, NULL);
4929       emitcode ("dec", "%s", l);
4930       if (size > 2)
4931         {
4932             if (!strcmp(l, "acc"))
4933             {
4934                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4935             }
4936             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4937                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4938                      IS_AOP_PREG (IC_RESULT (ic)))
4939             {
4940                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4941             }
4942             else
4943             {
4944                 emitcode ("mov", "a,#!constbyte",0xff);
4945                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4946             }
4947             l = aopGet (IC_RESULT (ic), MSB24, FALSE, FALSE, NULL);
4948             emitcode ("dec", "%s", l);
4949         }
4950       if (size > 3)
4951         {
4952             if (!strcmp(l, "acc"))
4953             {
4954                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4955             }
4956             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4957                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4958                      IS_AOP_PREG (IC_RESULT (ic)))
4959             {
4960                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4961             }
4962             else
4963             {
4964                 emitcode ("mov", "a,#!constbyte",0xff);
4965                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4966             }
4967             l = aopGet (IC_RESULT (ic), MSB32, FALSE, FALSE, NULL);
4968             emitcode ("dec", "%s", l);
4969         }
4970       if (emitTlbl)
4971         {
4972           emitLabel (tlbl);
4973         }
4974       return TRUE;
4975     }
4976
4977   /* if the sizes are greater than 1 then we cannot */
4978   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4979       AOP_SIZE (IC_LEFT (ic)) > 1)
4980     return FALSE;
4981
4982   /* we can if the aops of the left & result match or
4983      if they are in registers and the registers are the
4984      same */
4985   if (
4986        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4987        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4988        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4989     {
4990       char *l;
4991
4992       if (aopGetUsesAcc (IC_LEFT (ic), 0))
4993         {
4994           MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
4995           l = "a";
4996         }
4997       else
4998         {
4999           l = aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL);
5000         }
5001
5002       _startLazyDPSEvaluation ();
5003       while (icount--)
5004         {
5005           emitcode ("dec", "%s", l);
5006         }
5007       _endLazyDPSEvaluation ();
5008
5009       if (AOP_NEEDSACC (IC_RESULT (ic)))
5010         aopPut (IC_RESULT (ic), "a", 0);
5011
5012       return TRUE;
5013     }
5014
5015   return FALSE;
5016 }
5017
5018 /*-----------------------------------------------------------------*/
5019 /* addSign - complete with sign                                    */
5020 /*-----------------------------------------------------------------*/
5021 static void
5022 addSign (operand * result, int offset, int sign)
5023 {
5024   int size = (getDataSize (result) - offset);
5025   if (size > 0)
5026     {
5027       _startLazyDPSEvaluation();
5028       if (sign)
5029         {
5030           emitcode ("rlc", "a");
5031           emitcode ("subb", "a,acc");
5032           while (size--)
5033             {
5034               aopPut (result, "a", offset++);
5035             }
5036         }
5037       else
5038       {
5039         while (size--)
5040         {
5041           aopPut (result, zero, offset++);
5042         }
5043       }
5044       _endLazyDPSEvaluation();
5045     }
5046 }
5047
5048 /*-----------------------------------------------------------------*/
5049 /* genMinusBits - generates code for subtraction  of two bits      */
5050 /*-----------------------------------------------------------------*/
5051 static void
5052 genMinusBits (iCode * ic)
5053 {
5054   symbol *lbl = newiTempLabel (NULL);
5055
5056   D (emitcode (";", "genMinusBits"));
5057
5058   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
5059     {
5060       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5061       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
5062       emitcode ("cpl", "c");
5063       emitLabel (lbl);
5064       outBitC (IC_RESULT (ic));
5065     }
5066   else
5067     {
5068       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
5069       emitcode ("subb", "a,acc");
5070       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
5071       emitcode ("inc", "a");
5072       emitLabel (lbl);
5073       aopPut (IC_RESULT (ic), "a", 0);
5074       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
5075     }
5076 }
5077
5078 /*-----------------------------------------------------------------*/
5079 /* genMinus - generates code for subtraction                       */
5080 /*-----------------------------------------------------------------*/
5081 static void
5082 genMinus (iCode * ic)
5083 {
5084     int size, offset = 0;
5085     int rSize;
5086     long lit = 0L;
5087     bool pushResult;
5088
5089     D (emitcode (";", "genMinus"));
5090
5091     AOP_OP_3_NOFATAL(ic, pushResult);
5092
5093     if (!pushResult)
5094     {
5095       /* special cases :- */
5096       /* if both left & right are in bit space */
5097       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
5098           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5099         {
5100           genMinusBits (ic);
5101           goto release;
5102         }
5103
5104       /* if I can do an decrement instead
5105          of subtract then GOOD for ME */
5106       if (genMinusDec (ic) == TRUE)
5107         goto release;
5108
5109     }
5110
5111   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
5112
5113   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5114     {
5115       CLRC;
5116     }
5117   else
5118     {
5119       lit = (long) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5120       lit = -lit;
5121     }
5122
5123
5124   /* if literal, add a,#-lit, else normal subb */
5125   _startLazyDPSEvaluation ();
5126   while (size--) {
5127       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
5128           if (AOP_USESDPTR(IC_RIGHT(ic))) {
5129               emitcode ("mov","b,%s",
5130                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE, NULL));
5131               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5132               emitcode ("subb","a,b");
5133           } else {
5134               MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5135               emitcode ("subb", "a,%s",
5136                         aopGet (IC_RIGHT (ic), offset, FALSE, FALSE,
5137                                 DP2_RESULT_REG));
5138           }
5139       } else {
5140           MOVA (aopGet (IC_LEFT (ic), offset, FALSE, FALSE, NULL));
5141           /* first add without previous c */
5142           if (!offset) {
5143               if (!size && lit==-1) {
5144                   emitcode ("dec", "a");
5145               } else {
5146                   emitcode ("add", "a,#!constbyte",
5147                             (unsigned int) (lit & 0x0FFL));
5148               }
5149           } else {
5150               emitcode ("addc", "a,#!constbyte",
5151                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5152           }
5153       }
5154
5155       if (pushResult) {
5156           emitcode ("push", "acc");
5157       } else {
5158           aopPut (IC_RESULT (ic), "a", offset);
5159       }
5160       offset++;
5161   }
5162   _endLazyDPSEvaluation ();
5163
5164   if (pushResult)
5165     {
5166       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5167
5168       size = getDataSize (IC_LEFT (ic));
5169       rSize = getDataSize (IC_RESULT (ic));
5170
5171       ADJUST_PUSHED_RESULT(size, rSize);
5172
5173       _startLazyDPSEvaluation ();
5174       while (size--)
5175         {
5176           emitcode ("pop", "acc");
5177           aopPut (IC_RESULT (ic), "a", size);
5178         }
5179       _endLazyDPSEvaluation ();
5180     }
5181
5182   adjustArithmeticResult (ic);
5183
5184 release:
5185   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
5186   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5187   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5188 }
5189
5190
5191 /*-----------------------------------------------------------------*/
5192 /* genMultbits :- multiplication of bits                           */
5193 /*-----------------------------------------------------------------*/
5194 static void
5195 genMultbits (operand * left,
5196              operand * right,
5197              operand * result,
5198              iCode   * ic)
5199 {
5200   D (emitcode (";", "genMultbits"));
5201
5202   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
5203   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
5204   aopOp(result, ic, TRUE, FALSE);
5205   outBitC (result);
5206 }
5207
5208 /*-----------------------------------------------------------------*/
5209 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
5210 /*-----------------------------------------------------------------*/
5211 static void
5212 genMultOneByte (operand * left,
5213                 operand * right,
5214                 operand * result,
5215                 iCode   * ic)
5216 {
5217   symbol *lbl;
5218   int size;
5219   bool runtimeSign, compiletimeSign;
5220   bool lUnsigned, rUnsigned, pushedB;
5221
5222   /* (if two literals: the value is computed before) */
5223   /* if one literal, literal on the right */
5224   if (AOP_TYPE (left) == AOP_LIT)
5225     {
5226       operand *t = right;
5227       right = left;
5228       left = t;
5229       /* emitcode (";", "swapped left and right"); */
5230     }
5231   /* if no literal, unsigned on the right: shorter code */
5232   if (   AOP_TYPE (right) != AOP_LIT
5233       && SPEC_USIGN (getSpec (operandType (left))))
5234     {
5235       operand *t = right;
5236       right = left;
5237       left = t;
5238     }
5239
5240   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5241   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5242
5243   pushedB = pushB ();
5244
5245   if ((lUnsigned && rUnsigned)
5246 /* sorry, I don't know how to get size
5247    without calling aopOp (result,...);
5248    see Feature Request  */
5249       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
5250                    no need to take care about the signedness! */
5251     {
5252       /* just an unsigned 8 * 8 = 8 multiply
5253          or 8u * 8u = 16u */
5254       /* emitcode (";","unsigned"); */
5255       emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5256       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5257       emitcode ("mul", "ab");
5258
5259       _G.accInUse++;
5260       aopOp (result, ic, TRUE, FALSE);
5261       size = AOP_SIZE (result);
5262
5263       if (size < 1 || size > 2)
5264         {
5265           /* this should never happen */
5266           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5267                    size, __FILE__, lineno);
5268           exit (1);
5269         }
5270
5271       aopPut (result, "a", 0);
5272       _G.accInUse--;
5273       if (size == 2)
5274         aopPut (result, "b", 1);
5275
5276       popB (pushedB);
5277       return;
5278     }
5279
5280   /* we have to do a signed multiply */
5281   /* emitcode (";", "signed"); */
5282
5283   /* now sign adjust for both left & right */
5284
5285   /* let's see what's needed: */
5286   /* apply negative sign during runtime */
5287   runtimeSign = FALSE;
5288   /* negative sign from literals */
5289   compiletimeSign = FALSE;
5290
5291   if (!lUnsigned)
5292     {
5293       if (AOP_TYPE(left) == AOP_LIT)
5294         {
5295           /* signed literal */
5296           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5297           if (val < 0)
5298             compiletimeSign = TRUE;
5299         }
5300       else
5301         /* signed but not literal */
5302         runtimeSign = TRUE;
5303     }
5304
5305   if (!rUnsigned)
5306     {
5307       if (AOP_TYPE(right) == AOP_LIT)
5308         {
5309           /* signed literal */
5310           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5311           if (val < 0)
5312             compiletimeSign ^= TRUE;
5313         }
5314       else
5315         /* signed but not literal */
5316         runtimeSign = TRUE;
5317     }
5318
5319   /* initialize F0, which stores the runtime sign */
5320   if (runtimeSign)
5321     {
5322       if (compiletimeSign)
5323         emitcode ("setb", "F0"); /* set sign flag */
5324       else
5325         emitcode ("clr", "F0"); /* reset sign flag */
5326     }
5327
5328   /* save the signs of the operands */
5329   if (AOP_TYPE(right) == AOP_LIT)
5330     {
5331       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5332
5333       if (!rUnsigned && val < 0)
5334         emitcode ("mov", "b,#!constbyte", -val);
5335       else
5336         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
5337     }
5338   else /* ! literal */
5339     {
5340       if (rUnsigned)  /* emitcode (";", "signed"); */
5341         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5342       else
5343         {
5344           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5345           lbl = newiTempLabel (NULL);
5346           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5347           emitcode ("cpl", "F0"); /* complement sign flag */
5348           emitcode ("cpl", "a");  /* 2's complement */
5349           emitcode ("inc", "a");
5350           emitLabel (lbl);
5351           emitcode ("mov", "b,a");
5352         }
5353     }
5354
5355   if (AOP_TYPE(left) == AOP_LIT)
5356     {
5357       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5358
5359       if (!lUnsigned && val < 0)
5360         emitcode ("mov", "a,#!constbyte", -val);
5361       else
5362         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
5363     }
5364   else /* ! literal */
5365     {
5366       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5367
5368       if (!lUnsigned)  /* emitcode (";", "signed"); */
5369         {
5370           lbl = newiTempLabel (NULL);
5371           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5372           emitcode ("cpl", "F0"); /* complement sign flag */
5373           emitcode ("cpl", "a");  /* 2's complement */
5374           emitcode ("inc", "a");
5375           emitLabel (lbl);
5376         }
5377     }
5378
5379   /* now the multiplication */
5380   emitcode ("mul", "ab");
5381   _G.accInUse++;
5382   aopOp(result, ic, TRUE, FALSE);
5383   size = AOP_SIZE (result);
5384
5385   if (size < 1 || size > 2)
5386     {
5387       /* this should never happen */
5388       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
5389                size, __FILE__, lineno);
5390       exit (1);
5391     }
5392
5393   if (runtimeSign || compiletimeSign)
5394     {
5395       lbl = newiTempLabel (NULL);
5396       if (runtimeSign)
5397         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5398       emitcode ("cpl", "a"); /* lsb 2's complement */
5399       if (size != 2)
5400         emitcode ("inc", "a"); /* inc doesn't set carry flag */
5401       else
5402         {
5403           emitcode ("add", "a,#1"); /* this sets carry flag */
5404           emitcode ("xch", "a,b");
5405           emitcode ("cpl", "a"); /* msb 2's complement */
5406           emitcode ("addc", "a,#0");
5407           emitcode ("xch", "a,b");
5408         }
5409       emitLabel (lbl);
5410     }
5411   aopPut (result, "a", 0);
5412   _G.accInUse--;
5413   if (size == 2)
5414     aopPut (result, "b", 1);
5415
5416   popB (pushedB);
5417 }
5418
5419 /*-----------------------------------------------------------------*/
5420 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
5421 /*-----------------------------------------------------------------*/
5422 static void genMultTwoByte (operand *left, operand *right,
5423                             operand *result, iCode *ic)
5424 {
5425         sym_link *retype = getSpec(operandType(right));
5426         sym_link *letype = getSpec(operandType(left));
5427         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5428         symbol *lbl;
5429
5430         if (AOP_TYPE (left) == AOP_LIT) {
5431                 operand *t = right;
5432                 right = left;
5433                 left = t;
5434         }
5435         /* save EA bit in F1 */
5436         lbl = newiTempLabel(NULL);
5437         emitcode ("setb","F1");
5438         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5439         emitcode ("clr","F1");
5440         emitLabel (lbl);
5441
5442         /* load up MB with right */
5443         if (!umult) {
5444                 emitcode("clr","F0");
5445                 if (AOP_TYPE(right) == AOP_LIT) {
5446                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5447                         if (val < 0) {
5448                                 emitcode("setb","F0");
5449                                 val = -val;
5450                         }
5451                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5452                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5453                 } else {
5454                         lbl = newiTempLabel(NULL);
5455                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5456                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5457                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5458                         emitcode ("xch", "a,b");
5459                         emitcode ("cpl","a");
5460                         emitcode ("add", "a,#1");
5461                         emitcode ("xch", "a,b");
5462                         emitcode ("cpl", "a"); // msb
5463                         emitcode ("addc", "a,#0");
5464                         emitcode ("setb","F0");
5465                         emitLabel (lbl);
5466                         emitcode ("mov","mb,b");
5467                         emitcode ("mov","mb,a");
5468                 }
5469         } else {
5470                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5471                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5472         }
5473         /* load up MA with left */
5474         if (!umult) {
5475                 lbl = newiTempLabel(NULL);
5476                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5477                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5478                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5479                 emitcode ("xch", "a,b");
5480                 emitcode ("cpl","a");
5481                 emitcode ("add", "a,#1");
5482                 emitcode ("xch", "a,b");
5483                 emitcode ("cpl", "a"); // msb
5484                 emitcode ("addc","a,#0");
5485                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5486                 emitcode ("setb","F0");
5487                 emitLabel (lbl);
5488                 emitcode ("mov","ma,b");
5489                 emitcode ("mov","ma,a");
5490         } else {
5491                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5492                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5493         }
5494         /* wait for multiplication to finish */
5495         lbl = newiTempLabel(NULL);
5496         emitLabel (lbl);
5497         emitcode("mov","a,mcnt1");
5498         emitcode("anl","a,#!constbyte",0x80);
5499         emitcode("jnz","!tlabel",lbl->key+100);
5500
5501         freeAsmop (left, NULL, ic, TRUE);
5502         freeAsmop (right, NULL, ic,TRUE);
5503         aopOp(result, ic, TRUE, FALSE);
5504
5505         /* if unsigned then simple */
5506         if (umult) {
5507                 emitcode ("mov","a,ma");
5508                 if (AOP_SIZE(result) >= 4) aopPut(result,"a",3);
5509                 emitcode ("mov","a,ma");
5510                 if (AOP_SIZE(result) >= 3) aopPut(result,"a",2);
5511                 aopPut(result,"ma",1);
5512                 aopPut(result,"ma",0);
5513         } else {
5514                 emitcode("push","ma");
5515                 emitcode("push","ma");
5516                 emitcode("push","ma");
5517                 MOVA("ma");
5518                 /* negate result if needed */
5519                 lbl = newiTempLabel(NULL);
5520                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5521                 emitcode("cpl","a");
5522                 emitcode("add","a,#1");
5523                 emitLabel (lbl);
5524                 if (AOP_TYPE(result) == AOP_ACC)
5525                 {
5526                     D (emitcode(";", "ACC special case."));
5527                     /* We know result is the only live aop, and
5528                      * it's obviously not a DPTR2, so AP is available.
5529                      */
5530                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5531                 }
5532                 else
5533                 {
5534                     aopPut(result,"a",0);
5535                 }
5536
5537                 emitcode("pop","acc");
5538                 lbl = newiTempLabel(NULL);
5539                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5540                 emitcode("cpl","a");
5541                 emitcode("addc","a,#0");
5542                 emitLabel (lbl);
5543                 aopPut(result,"a",1);
5544                 emitcode("pop","acc");
5545                 if (AOP_SIZE(result) >= 3) {
5546                         lbl = newiTempLabel(NULL);
5547                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5548                         emitcode("cpl","a");
5549                         emitcode("addc","a,#0");
5550                         emitLabel (lbl);
5551                         aopPut(result,"a",2);
5552                 }
5553                 emitcode("pop","acc");
5554                 if (AOP_SIZE(result) >= 4) {
5555                         lbl = newiTempLabel(NULL);
5556                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5557                         emitcode("cpl","a");
5558                         emitcode("addc","a,#0");
5559                         emitLabel (lbl);
5560                         aopPut(result,"a",3);
5561                 }
5562                 if (AOP_TYPE(result) == AOP_ACC)
5563                 {
5564                     /* We stashed the result away above. */
5565                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5566                 }
5567
5568         }
5569         freeAsmop (result, NULL, ic, TRUE);
5570
5571         /* restore EA bit in F1 */
5572         lbl = newiTempLabel(NULL);
5573         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5574         emitcode ("setb","EA");
5575         emitLabel (lbl);
5576         return ;
5577 }
5578
5579 /*-----------------------------------------------------------------*/
5580 /* genMult - generates code for multiplication                     */
5581 /*-----------------------------------------------------------------*/
5582 static void
5583 genMult (iCode * ic)
5584 {
5585   operand *left = IC_LEFT (ic);
5586   operand *right = IC_RIGHT (ic);
5587   operand *result = IC_RESULT (ic);
5588
5589   D (emitcode (";", "genMult"));
5590
5591   /* assign the asmops */
5592   AOP_OP_2 (ic);
5593
5594   /* special cases first */
5595   /* both are bits */
5596   if (AOP_TYPE (left) == AOP_CRY &&
5597       AOP_TYPE (right) == AOP_CRY)
5598     {
5599       genMultbits (left, right, result, ic);
5600       goto release;
5601     }
5602
5603   /* if both are of size == 1 */
5604   if (AOP_SIZE (left) == 1 &&
5605       AOP_SIZE (right) == 1)
5606     {
5607       genMultOneByte (left, right, result, ic);
5608       goto release;
5609     }
5610
5611   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5612           /* use the ds390 ARITHMETIC accel UNIT */
5613           genMultTwoByte (left, right, result, ic);
5614           return ;
5615   }
5616   /* should have been converted to function call */
5617   assert (0);
5618
5619 release:
5620   freeAsmop (result, NULL, ic, TRUE);
5621   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5622   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5623 }
5624
5625 /*-----------------------------------------------------------------*/
5626 /* genDivbits :- division of bits                                  */
5627 /*-----------------------------------------------------------------*/
5628 static void
5629 genDivbits (operand * left,
5630             operand * right,
5631             operand * result,
5632             iCode   * ic)
5633 {
5634   char *l;
5635   bool pushedB;
5636
5637   D(emitcode (";", "genDivbits"));
5638
5639   pushedB = pushB ();
5640
5641   /* the result must be bit */
5642   LOAD_AB_FOR_DIV (left, right, l);
5643   emitcode ("div", "ab");
5644   emitcode ("rrc", "a");
5645   aopOp(result, ic, TRUE, FALSE);
5646
5647   popB (pushedB);
5648
5649   aopPut (result, "c", 0);
5650 }
5651
5652 /*-----------------------------------------------------------------*/
5653 /* genDivOneByte : 8 bit division                                  */
5654 /*-----------------------------------------------------------------*/
5655 static void
5656 genDivOneByte (operand * left,
5657                operand * right,
5658                operand * result,
5659                iCode   * ic)
5660 {
5661   bool lUnsigned, rUnsigned, pushedB;
5662   bool runtimeSign, compiletimeSign;
5663   char *l;
5664   symbol *lbl;
5665   int size, offset;
5666
5667   D(emitcode (";", "genDivOneByte"));
5668
5669   offset = 1;
5670   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5671   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5672
5673   pushedB = pushB ();
5674
5675   /* signed or unsigned */
5676   if (lUnsigned && rUnsigned)
5677     {
5678       /* unsigned is easy */
5679       LOAD_AB_FOR_DIV (left, right, l);
5680       emitcode ("div", "ab");
5681
5682       _G.accInUse++;
5683       aopOp (result, ic, TRUE, FALSE);
5684       aopPut (result, "a", 0);
5685       _G.accInUse--;
5686
5687       size = AOP_SIZE (result) - 1;
5688
5689       while (size--)
5690         aopPut (result, zero, offset++);
5691
5692       popB (pushedB);
5693       return;
5694     }
5695
5696   /* signed is a little bit more difficult */
5697
5698   /* now sign adjust for both left & right */
5699
5700   /* let's see what's needed: */
5701   /* apply negative sign during runtime */
5702   runtimeSign = FALSE;
5703   /* negative sign from literals */
5704   compiletimeSign = FALSE;
5705
5706   if (!lUnsigned)
5707     {
5708       if (AOP_TYPE(left) == AOP_LIT)
5709         {
5710           /* signed literal */
5711           signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5712           if (val < 0)
5713             compiletimeSign = TRUE;
5714         }
5715       else
5716         /* signed but not literal */
5717         runtimeSign = TRUE;
5718     }
5719
5720   if (!rUnsigned)
5721     {
5722       if (AOP_TYPE(right) == AOP_LIT)
5723         {
5724           /* signed literal */
5725           signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5726           if (val < 0)
5727             compiletimeSign ^= TRUE;
5728         }
5729       else
5730         /* signed but not literal */
5731         runtimeSign = TRUE;
5732     }
5733
5734   /* initialize F0, which stores the runtime sign */
5735   if (runtimeSign)
5736     {
5737       if (compiletimeSign)
5738         emitcode ("setb", "F0"); /* set sign flag */
5739       else
5740         emitcode ("clr", "F0"); /* reset sign flag */
5741     }
5742
5743   /* save the signs of the operands */
5744   if (AOP_TYPE(right) == AOP_LIT)
5745     {
5746       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
5747
5748       if (!rUnsigned && val < 0)
5749         emitcode ("mov", "b,#0x%02x", -val);
5750       else
5751         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5752     }
5753   else /* ! literal */
5754     {
5755       if (rUnsigned)
5756         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
5757       else
5758         {
5759           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
5760           lbl = newiTempLabel (NULL);
5761           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5762           emitcode ("cpl", "F0"); /* complement sign flag */
5763           emitcode ("cpl", "a");  /* 2's complement */
5764           emitcode ("inc", "a");
5765           emitLabel (lbl);
5766           emitcode ("mov", "b,a");
5767         }
5768     }
5769
5770   if (AOP_TYPE(left) == AOP_LIT)
5771     {
5772       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
5773
5774       if (!lUnsigned && val < 0)
5775         emitcode ("mov", "a,#0x%02x", -val);
5776       else
5777         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5778     }
5779   else /* ! literal */
5780     {
5781       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
5782
5783       if (!lUnsigned)
5784         {
5785           lbl = newiTempLabel (NULL);
5786           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5787           emitcode ("cpl", "F0"); /* complement sign flag */
5788           emitcode ("cpl", "a");  /* 2's complement */
5789           emitcode ("inc", "a");
5790           emitLabel (lbl);
5791         }
5792     }
5793
5794   /* now the division */
5795   emitcode ("nop", "; workaround for DS80C390 div bug.");
5796   emitcode ("div", "ab");
5797
5798   if (runtimeSign || compiletimeSign)
5799     {
5800       lbl = newiTempLabel (NULL);
5801       if (runtimeSign)
5802         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5803       emitcode ("cpl", "a"); /* lsb 2's complement */
5804       emitcode ("inc", "a");
5805       emitLabel (lbl);
5806
5807       _G.accInUse++;
5808       aopOp (result, ic, TRUE, FALSE);
5809       size = AOP_SIZE (result) - 1;
5810
5811       if (size > 0)
5812         {
5813           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5814              then the result will be in b, a */
5815           emitcode ("mov", "b,a"); /* 1 */
5816           /* msb is 0x00 or 0xff depending on the sign */
5817           if (runtimeSign)
5818             {
5819               emitcode ("mov",  "c,F0");
5820               emitcode ("subb", "a,acc");
5821               emitcode ("xch",  "a,b"); /* 2 */
5822               while (size--)
5823                 aopPut (result, "b", offset++); /* write msb's */
5824             }
5825           else /* compiletimeSign */
5826             while (size--)
5827               aopPut (result, "#0xff", offset++); /* write msb's */
5828         }
5829       aopPut (result, "a", 0); /* 3: write lsb */
5830     }
5831   else
5832     {
5833       _G.accInUse++;
5834       aopOp(result, ic, TRUE, FALSE);
5835       size = AOP_SIZE (result) - 1;
5836
5837       aopPut (result, "a", 0);
5838       while (size--)
5839         aopPut (result, zero, offset++);
5840     }
5841   _G.accInUse--;
5842   popB (pushedB);
5843 }
5844
5845 /*-----------------------------------------------------------------*/
5846 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5847 /*-----------------------------------------------------------------*/
5848 static void genDivTwoByte (operand *left, operand *right,
5849                             operand *result, iCode *ic)
5850 {
5851         sym_link *retype = getSpec(operandType(right));
5852         sym_link *letype = getSpec(operandType(left));
5853         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5854         symbol *lbl;
5855
5856         /* save EA bit in F1 */
5857         lbl = newiTempLabel(NULL);
5858         emitcode ("setb","F1");
5859         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5860         emitcode ("clr","F1");
5861         emitLabel (lbl);
5862
5863         /* load up MA with left */
5864         if (!umult) {
5865                 emitcode("clr","F0");
5866                 lbl = newiTempLabel(NULL);
5867                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
5868                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
5869                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5870                 emitcode ("xch", "a,b");
5871                 emitcode ("cpl","a");
5872                 emitcode ("add", "a,#1");
5873                 emitcode ("xch", "a,b");
5874                 emitcode ("cpl", "a"); // msb
5875                 emitcode ("addc","a,#0");
5876                 emitcode ("setb","F0");
5877                 emitLabel (lbl);
5878                 emitcode ("mov","ma,b");
5879                 emitcode ("mov","ma,a");
5880         } else {
5881                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
5882                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
5883         }
5884
5885         /* load up MB with right */
5886         if (!umult) {
5887                 if (AOP_TYPE(right) == AOP_LIT) {
5888                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
5889                         if (val < 0) {
5890                                 lbl = newiTempLabel(NULL);
5891                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5892                                 emitcode("setb","F0");
5893                                 emitLabel (lbl);
5894                                 val = -val;
5895                         }
5896                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5897                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5898                 } else {
5899                         lbl = newiTempLabel(NULL);
5900                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
5901                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
5902                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5903                         emitcode ("xch", "a,b");
5904                         emitcode ("cpl","a");
5905                         emitcode ("add", "a,#1");
5906                         emitcode ("xch", "a,b");
5907                         emitcode ("cpl", "a"); // msb
5908                         emitcode ("addc", "a,#0");
5909                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5910                         emitcode ("setb","F0");
5911                         emitLabel (lbl);
5912                         emitcode ("mov","mb,b");
5913                         emitcode ("mov","mb,a");
5914                 }
5915         } else {
5916                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
5917                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
5918         }
5919
5920         /* wait for multiplication to finish */
5921         lbl = newiTempLabel(NULL);
5922         emitLabel (lbl);
5923         emitcode("mov","a,mcnt1");
5924         emitcode("anl","a,#!constbyte",0x80);
5925         emitcode("jnz","!tlabel",lbl->key+100);
5926
5927         freeAsmop (left, NULL, ic, TRUE);
5928         freeAsmop (right, NULL, ic,TRUE);
5929         aopOp(result, ic, TRUE, FALSE);
5930
5931         /* if unsigned then simple */
5932         if (umult) {
5933                 aopPut(result,"ma",1);
5934                 aopPut(result,"ma",0);
5935         } else {
5936                 emitcode("push","ma");
5937                 MOVA("ma");
5938                 /* negate result if needed */
5939                 lbl = newiTempLabel(NULL);
5940                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5941                 emitcode("cpl","a");
5942                 emitcode("add","a,#1");
5943                 emitLabel (lbl);
5944                 aopPut(result,"a",0);
5945                 emitcode("pop","acc");
5946                 lbl = newiTempLabel(NULL);
5947                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5948                 emitcode("cpl","a");
5949                 emitcode("addc","a,#0");
5950                 emitLabel (lbl);
5951                 aopPut(result,"a",1);
5952         }
5953         freeAsmop (result, NULL, ic, TRUE);
5954         /* restore EA bit in F1 */
5955         lbl = newiTempLabel(NULL);
5956         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5957         emitcode ("setb","EA");
5958         emitLabel (lbl);
5959         return ;
5960 }
5961
5962 /*-----------------------------------------------------------------*/
5963 /* genDiv - generates code for division                            */
5964 /*-----------------------------------------------------------------*/
5965 static void
5966 genDiv (iCode * ic)
5967 {
5968   operand *left = IC_LEFT (ic);
5969   operand *right = IC_RIGHT (ic);
5970   operand *result = IC_RESULT (ic);
5971
5972   D (emitcode (";", "genDiv"));
5973
5974   /* assign the amsops */
5975   AOP_OP_2 (ic);
5976
5977   /* special cases first */
5978   /* both are bits */
5979   if (AOP_TYPE (left) == AOP_CRY &&
5980       AOP_TYPE (right) == AOP_CRY)
5981     {
5982       genDivbits (left, right, result, ic);
5983       goto release;
5984     }
5985
5986   /* if both are of size == 1 */
5987   if (AOP_SIZE (left) == 1 &&
5988       AOP_SIZE (right) == 1)
5989     {
5990       genDivOneByte (left, right, result, ic);
5991       goto release;
5992     }
5993
5994   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5995           /* use the ds390 ARITHMETIC accel UNIT */
5996           genDivTwoByte (left, right, result, ic);
5997           return ;
5998   }
5999   /* should have been converted to function call */
6000   assert (0);
6001 release:
6002   freeAsmop (result, NULL, ic, TRUE);
6003   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6004   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6005 }
6006
6007 /*-----------------------------------------------------------------*/
6008 /* genModbits :- modulus of bits                                   */
6009 /*-----------------------------------------------------------------*/
6010 static void
6011 genModbits (operand * left,
6012             operand * right,
6013             operand * result,
6014             iCode   * ic)
6015 {
6016   char *l;
6017   bool pushedB;
6018
6019   D (emitcode (";", "genModbits"));
6020
6021   pushedB = pushB ();
6022
6023   /* the result must be bit */
6024   LOAD_AB_FOR_DIV (left, right, l);
6025   emitcode ("div", "ab");
6026   emitcode ("mov", "a,b");
6027   emitcode ("rrc", "a");
6028   aopOp(result, ic, TRUE, FALSE);
6029
6030   popB (pushedB);
6031
6032   aopPut (result, "c", 0);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* genModOneByte : 8 bit modulus                                   */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 genModOneByte (operand * left,
6040                operand * right,
6041                operand * result,
6042                iCode   * ic)
6043 {
6044   bool lUnsigned, rUnsigned, pushedB;
6045   bool runtimeSign, compiletimeSign;
6046   char *l;
6047   symbol *lbl;
6048   int size, offset;
6049
6050   D (emitcode (";", "genModOneByte"));
6051
6052   offset = 1;
6053   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
6054   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
6055
6056   pushedB = pushB ();
6057
6058   /* signed or unsigned */
6059   if (lUnsigned && rUnsigned)
6060     {
6061       /* unsigned is easy */
6062       LOAD_AB_FOR_DIV (left, right, l);
6063       emitcode ("div", "ab");
6064       aopOp (result, ic, TRUE, FALSE);
6065       aopPut (result, "b", 0);
6066
6067       for (size = AOP_SIZE (result) - 1; size--;)
6068         aopPut (result, zero, offset++);
6069
6070       popB (pushedB);
6071       return;
6072     }
6073
6074   /* signed is a little bit more difficult */
6075
6076   /* now sign adjust for both left & right */
6077
6078   /* modulus: sign of the right operand has no influence on the result! */
6079   if (AOP_TYPE(right) == AOP_LIT)
6080     {
6081       signed char val = (char) ulFromVal (AOP (right)->aopu.aop_lit);
6082
6083       if (!rUnsigned && val < 0)
6084         emitcode ("mov", "b,#0x%02x", -val);
6085       else
6086         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
6087     }
6088   else /* not literal */
6089     {
6090       if (rUnsigned)
6091         emitcode ("mov", "b,%s", aopGet (right, 0, FALSE, FALSE, NULL));
6092       else
6093         {
6094           MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
6095           lbl = newiTempLabel (NULL);
6096           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6097           emitcode ("cpl", "a");  /* 2's complement */
6098           emitcode ("inc", "a");
6099           emitLabel (lbl);
6100           emitcode ("mov", "b,a");
6101         }
6102     }
6103
6104   /* let's see what's needed: */
6105   /* apply negative sign during runtime */
6106   runtimeSign = FALSE;
6107   /* negative sign from literals */
6108   compiletimeSign = FALSE;
6109
6110   /* sign adjust left side */
6111   if (AOP_TYPE(left) == AOP_LIT)
6112     {
6113       signed char val = (char) ulFromVal (AOP (left)->aopu.aop_lit);
6114
6115       if (!lUnsigned && val < 0)
6116         {
6117           compiletimeSign = TRUE; /* set sign flag */
6118           emitcode ("mov", "a,#0x%02x", -val);
6119         }
6120       else
6121         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
6122     }
6123   else /* ! literal */
6124     {
6125       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
6126
6127       if (!lUnsigned)
6128         {
6129           runtimeSign = TRUE;
6130           emitcode ("clr", "F0"); /* clear sign flag */
6131
6132           lbl = newiTempLabel (NULL);
6133           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
6134           emitcode ("setb", "F0"); /* set sign flag */
6135           emitcode ("cpl", "a");   /* 2's complement */
6136           emitcode ("inc", "a");
6137           emitLabel (lbl);
6138         }
6139     }
6140
6141   /* now the modulus */
6142   emitcode ("nop", "; workaround for DS80C390 div bug.");
6143   emitcode ("div", "ab");
6144
6145   if (runtimeSign || compiletimeSign)
6146     {
6147       emitcode ("mov", "a,b");
6148       lbl = newiTempLabel (NULL);
6149       if (runtimeSign)
6150         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
6151       emitcode ("cpl", "a"); /* lsb 2's complement */
6152       emitcode ("inc", "a");
6153       emitLabel (lbl);
6154
6155       _G.accInUse++;
6156       aopOp (result, ic, TRUE, FALSE);
6157       size = AOP_SIZE (result) - 1;
6158
6159       if (size > 0)
6160         {
6161           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
6162              then the result will be in b, a */
6163           emitcode ("mov", "b,a"); /* 1 */
6164           /* msb is 0x00 or 0xff depending on the sign */
6165           if (runtimeSign)
6166             {
6167               emitcode ("mov",  "c,F0");
6168               emitcode ("subb", "a,acc");
6169               emitcode ("xch",  "a,b"); /* 2 */
6170               while (size--)
6171                 aopPut (result, "b", offset++); /* write msb's */
6172             }
6173           else /* compiletimeSign */
6174             while (size--)
6175               aopPut (result, "#0xff", offset++); /* write msb's */
6176         }
6177       aopPut (result, "a", 0); /* 3: write lsb */
6178     }
6179   else
6180     {
6181       _G.accInUse++;
6182       aopOp(result, ic, TRUE, FALSE);
6183       size = AOP_SIZE (result) - 1;
6184
6185       aopPut (result, "b", 0);
6186       while (size--)
6187         aopPut (result, zero, offset++);
6188     }
6189   _G.accInUse--;
6190   popB (pushedB);
6191 }
6192
6193 /*-----------------------------------------------------------------*/
6194 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
6195 /*-----------------------------------------------------------------*/
6196 static void genModTwoByte (operand *left, operand *right,
6197                             operand *result, iCode *ic)
6198 {
6199         sym_link *retype = getSpec(operandType(right));
6200         sym_link *letype = getSpec(operandType(left));
6201         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
6202         symbol *lbl;
6203
6204         /* load up MA with left */
6205         /* save EA bit in F1 */
6206         lbl = newiTempLabel(NULL);
6207         emitcode ("setb","F1");
6208         emitcode ("jbc","EA,!tlabel",lbl->key+100);
6209         emitcode ("clr","F1");
6210         emitLabel (lbl);
6211
6212         if (!umult) {
6213                 lbl = newiTempLabel(NULL);
6214                 emitcode ("mov","b,%s",aopGet(left,0,FALSE,FALSE,NULL));
6215                 emitcode ("mov","a,%s",aopGet(left,1,FALSE,FALSE,NULL));
6216                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6217                 emitcode ("xch", "a,b");
6218                 emitcode ("cpl","a");
6219                 emitcode ("add", "a,#1");
6220                 emitcode ("xch", "a,b");
6221                 emitcode ("cpl", "a"); // msb
6222                 emitcode ("addc","a,#0");
6223                 emitLabel (lbl);
6224                 emitcode ("mov","ma,b");
6225                 emitcode ("mov","ma,a");
6226         } else {
6227                 emitcode ("mov","ma,%s",aopGet(left,0,FALSE,FALSE,NULL));
6228                 emitcode ("mov","ma,%s",aopGet(left,1,FALSE,FALSE,NULL));
6229         }
6230
6231         /* load up MB with right */
6232         if (!umult) {
6233                 if (AOP_TYPE(right) == AOP_LIT) {
6234                         int val=(int) ulFromVal (AOP (right)->aopu.aop_lit);
6235                         if (val < 0) {
6236                                 val = -val;
6237                         }
6238                         emitcode ("mov","mb,#!constbyte",val & 0xff);
6239                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
6240                 } else {
6241                         lbl = newiTempLabel(NULL);
6242                         emitcode ("mov","b,%s",aopGet(right,0,FALSE,FALSE,NULL));
6243                         emitcode ("mov","a,%s",aopGet(right,1,FALSE,FALSE,NULL));
6244                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
6245                         emitcode ("xch", "a,b");
6246                         emitcode ("cpl","a");
6247                         emitcode ("add", "a,#1");
6248                         emitcode ("xch", "a,b");
6249                         emitcode ("cpl", "a"); // msb
6250                         emitcode ("addc", "a,#0");
6251                         emitLabel (lbl);
6252                         emitcode ("mov","mb,b");
6253                         emitcode ("mov","mb,a");
6254                 }
6255         } else {
6256                 emitcode ("mov","mb,%s",aopGet(right,0,FALSE,FALSE,NULL));
6257                 emitcode ("mov","mb,%s",aopGet(right,1,FALSE,FALSE,NULL));
6258         }
6259
6260         /* wait for multiplication to finish */
6261         lbl = newiTempLabel(NULL);
6262         emitLabel (lbl);
6263         emitcode("mov","a,mcnt1");
6264         emitcode("anl","a,#!constbyte",0x80);
6265         emitcode("jnz","!tlabel",lbl->key+100);
6266
6267         freeAsmop (left, NULL, ic, TRUE);
6268         freeAsmop (right, NULL, ic,TRUE);
6269         aopOp(result, ic, TRUE, FALSE);
6270
6271         aopPut(result,"mb",1);
6272         aopPut(result,"mb",0);
6273         freeAsmop (result, NULL, ic, TRUE);
6274
6275         /* restore EA bit in F1 */
6276         lbl = newiTempLabel(NULL);
6277         emitcode ("jnb","F1,!tlabel",lbl->key+100);
6278         emitcode ("setb","EA");
6279         emitLabel (lbl);
6280 }
6281
6282 /*-----------------------------------------------------------------*/
6283 /* genMod - generates code for division                            */
6284 /*-----------------------------------------------------------------*/
6285 static void
6286 genMod (iCode * ic)
6287 {
6288   operand *left = IC_LEFT (ic);
6289   operand *right = IC_RIGHT (ic);
6290   operand *result = IC_RESULT (ic);
6291
6292   D (emitcode (";", "genMod"));
6293
6294   /* assign the asmops */
6295   AOP_OP_2 (ic);
6296
6297   /* special cases first */
6298   /* both are bits */
6299   if (AOP_TYPE (left) == AOP_CRY &&
6300       AOP_TYPE (right) == AOP_CRY)
6301     {
6302       genModbits (left, right, result, ic);
6303       goto release;
6304     }
6305
6306   /* if both are of size == 1 */
6307   if (AOP_SIZE (left) == 1 &&
6308       AOP_SIZE (right) == 1)
6309     {
6310       genModOneByte (left, right, result, ic);
6311       goto release;
6312     }
6313
6314   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
6315           /* use the ds390 ARITHMETIC accel UNIT */
6316           genModTwoByte (left, right, result, ic);
6317           return ;
6318   }
6319
6320   /* should have been converted to function call */
6321   assert (0);
6322
6323 release:
6324   freeAsmop (result, NULL, ic, TRUE);
6325   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6326   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6327 }
6328
6329 /*-----------------------------------------------------------------*/
6330 /* genIfxJump :- will create a jump depending on the ifx           */
6331 /*-----------------------------------------------------------------*/
6332 static void
6333 genIfxJump (iCode * ic, char *jval)
6334 {
6335   symbol *jlbl;
6336   symbol *tlbl = newiTempLabel (NULL);
6337   char *inst;
6338
6339   D (emitcode (";", "genIfxJump"));
6340
6341   /* if true label then we jump if condition
6342      supplied is true */
6343   if (IC_TRUE (ic))
6344     {
6345       jlbl = IC_TRUE (ic);
6346       inst = ((strcmp (jval, "a") == 0 ? "jz" :
6347                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
6348     }
6349   else
6350     {
6351       /* false label is present */
6352       jlbl = IC_FALSE (ic);
6353       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
6354                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
6355     }
6356   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
6357     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
6358   else
6359     emitcode (inst, "!tlabel", tlbl->key + 100);
6360   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
6361   emitLabel (tlbl);
6362
6363   /* mark the icode as generated */
6364   ic->generated = 1;
6365 }
6366
6367 /*-----------------------------------------------------------------*/
6368 /* genCmp :- greater or less than comparison                       */
6369 /*-----------------------------------------------------------------*/
6370 static void
6371 genCmp (operand * left, operand * right,
6372         iCode * ic, iCode * ifx, int sign)
6373 {
6374   int size, offset = 0;
6375   unsigned long lit = 0L;
6376   operand *result;
6377
6378   D (emitcode (";", "genCmp"));
6379
6380   result = IC_RESULT (ic);
6381
6382   /* if left & right are bit variables */
6383   if (AOP_TYPE (left) == AOP_CRY &&
6384       AOP_TYPE (right) == AOP_CRY)
6385     {
6386       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6387       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6388     }
6389   else
6390     {
6391       /* subtract right from left if at the
6392          end the carry flag is set then we know that
6393          left is greater than right */
6394       size = max (AOP_SIZE (left), AOP_SIZE (right));
6395
6396       /* if unsigned char cmp with lit, do cjne left,#right,zz */
6397       if ((size == 1) && !sign &&
6398           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
6399         {
6400           symbol *lbl = newiTempLabel (NULL);
6401           emitcode ("cjne", "%s,%s,!tlabel",
6402                     aopGet (left, offset, FALSE, FALSE, NULL),
6403                     aopGet (right, offset, FALSE, FALSE, NULL),
6404                     lbl->key + 100);
6405           emitLabel (lbl);
6406         }
6407       else
6408         {
6409           if (AOP_TYPE (right) == AOP_LIT)
6410             {
6411               lit = ulFromVal (AOP (right)->aopu.aop_lit);
6412               /* optimize if(x < 0) or if(x >= 0) */
6413               if (lit == 0L)
6414                 {
6415                   if (!sign)
6416                     {
6417                       CLRC;
6418                     }
6419                   else
6420                     {
6421                       MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
6422
6423                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6424                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6425
6426                       aopOp (result, ic, FALSE, FALSE);
6427
6428                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
6429                         {
6430                           freeAsmop (result, NULL, ic, TRUE);
6431                           genIfxJump (ifx, "acc.7");
6432                           return;
6433                         }
6434                       else
6435                         {
6436                           emitcode ("rlc", "a");
6437                         }
6438                       goto release_freedLR;
6439                     }
6440                   goto release;
6441                 }
6442             }
6443           CLRC;
6444           while (size--)
6445             {
6446               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
6447               MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6448               // emitcode (";", "genCmp #2");
6449               if (sign && (size == 0))
6450                 {
6451                   // emitcode (";", "genCmp #3");
6452                   emitcode ("xrl", "a,#!constbyte",0x80);
6453                   if (AOP_TYPE (right) == AOP_LIT)
6454                     {
6455                       unsigned long lit = ulFromVal (AOP (right)->aopu.aop_lit);
6456                       // emitcode (";", "genCmp #3.1");
6457                       emitcode ("subb", "a,#!constbyte",
6458                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6459                     }
6460                   else
6461                     {
6462                       // emitcode (";", "genCmp #3.2");
6463                       saveAccWarn = 0;
6464                       MOVB (aopGet (right, offset++, FALSE, FALSE, "b"));
6465                       saveAccWarn = DEFAULT_ACC_WARNING;
6466                       emitcode ("xrl", "b,#!constbyte",0x80);
6467                       emitcode ("subb", "a,b");
6468                     }
6469                 }
6470               else
6471                 {
6472                   const char *s;
6473
6474                   // emitcode (";", "genCmp #4");
6475                   saveAccWarn = 0;
6476                   s = aopGet (right, offset++, FALSE, FALSE, "b");
6477                   saveAccWarn = DEFAULT_ACC_WARNING;
6478
6479                   emitcode ("subb", "a,%s", s);
6480                 }
6481             }
6482         }
6483     }
6484
6485 release:
6486 /* Don't need the left & right operands any more; do need the result. */
6487   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6488   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6489
6490   aopOp (result, ic, FALSE, FALSE);
6491
6492 release_freedLR:
6493
6494   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6495     {
6496       outBitC (result);
6497     }
6498   else
6499     {
6500       /* if the result is used in the next
6501          ifx conditional branch then generate
6502          code a little differently */
6503       if (ifx)
6504         {
6505           genIfxJump (ifx, "c");
6506         }
6507       else
6508         {
6509           outBitC (result);
6510         }
6511       /* leave the result in acc */
6512     }
6513   freeAsmop (result, NULL, ic, TRUE);
6514 }
6515
6516 /*-----------------------------------------------------------------*/
6517 /* genCmpGt :- greater than comparison                             */
6518 /*-----------------------------------------------------------------*/
6519 static void
6520 genCmpGt (iCode * ic, iCode * ifx)
6521 {
6522   operand *left, *right;
6523   sym_link *letype, *retype;
6524   int sign;
6525
6526   D (emitcode (";", "genCmpGt"));
6527
6528   left = IC_LEFT (ic);
6529   right = IC_RIGHT (ic);
6530
6531   letype = getSpec (operandType (left));
6532   retype = getSpec (operandType (right));
6533   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6534
6535   /* assign the left & right amsops */
6536   AOP_OP_2 (ic);
6537
6538   genCmp (right, left, ic, ifx, sign);
6539 }
6540
6541 /*-----------------------------------------------------------------*/
6542 /* genCmpLt - less than comparisons                                */
6543 /*-----------------------------------------------------------------*/
6544 static void
6545 genCmpLt (iCode * ic, iCode * ifx)
6546 {
6547   operand *left, *right;
6548   sym_link *letype, *retype;
6549   int sign;
6550
6551   D (emitcode (";", "genCmpLt"));
6552
6553   left = IC_LEFT (ic);
6554   right = IC_RIGHT (ic);
6555
6556   letype = getSpec (operandType (left));
6557   retype = getSpec (operandType (right));
6558   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6559
6560   /* assign the left & right amsops */
6561   AOP_OP_2 (ic);
6562
6563   genCmp (left, right, ic, ifx, sign);
6564 }
6565
6566 /*-----------------------------------------------------------------*/
6567 /* gencjneshort - compare and jump if not equal                    */
6568 /*-----------------------------------------------------------------*/
6569 static void
6570 gencjneshort (operand * left, operand * right, symbol * lbl)
6571 {
6572   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6573   int offset = 0;
6574   unsigned long lit = 0L;
6575
6576   D (emitcode (";", "gencjneshort"));
6577
6578   /* if the left side is a literal or
6579      if the right is in a pointer register and left
6580      is not */
6581   if ((AOP_TYPE (left) == AOP_LIT) ||
6582       (AOP_TYPE (left) == AOP_IMMD) ||
6583       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6584     {
6585       operand *t = right;
6586       right = left;
6587       left = t;
6588     }
6589
6590   if (AOP_TYPE (right) == AOP_LIT)
6591     lit = ulFromVal (AOP (right)->aopu.aop_lit);
6592
6593   if (opIsGptr (left) || opIsGptr (right))
6594     {
6595       /* We are comparing a generic pointer to something.
6596        * Exclude the generic type byte from the comparison.
6597        */
6598       size--;
6599       D (emitcode (";", "cjneshort: generic ptr special case."););
6600     }
6601
6602
6603   /* if the right side is a literal then anything goes */
6604   if (AOP_TYPE (right) == AOP_LIT &&
6605       AOP_TYPE (left) != AOP_DIR)
6606     {
6607       while (size--)
6608         {
6609           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6610           emitcode ("cjne", "a,%s,!tlabel",
6611                     aopGet (right, offset, FALSE, FALSE, NULL),
6612                     lbl->key + 100);
6613           offset++;
6614         }
6615     }
6616
6617   /* if the right side is in a register or in direct space or
6618      if the left is a pointer register & right is not */
6619   else if (AOP_TYPE (right) == AOP_REG ||
6620            AOP_TYPE (right) == AOP_DIR ||
6621            AOP_TYPE (right) == AOP_LIT ||
6622            AOP_TYPE (right) == AOP_IMMD ||
6623            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6624            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6625     {
6626       while (size--)
6627         {
6628           MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
6629           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6630               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6631             emitcode ("jnz", "!tlabel", lbl->key + 100);
6632           else
6633             emitcode ("cjne", "a,%s,!tlabel",
6634                       aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG),
6635                       lbl->key + 100);
6636           offset++;
6637         }
6638     }
6639   else
6640     {
6641       /* right is a pointer reg need both a & b */
6642       while (size--)
6643         {
6644           MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
6645           MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
6646           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6647           offset++;
6648         }
6649     }
6650 }
6651
6652 /*-----------------------------------------------------------------*/
6653 /* gencjne - compare and jump if not equal                         */
6654 /*-----------------------------------------------------------------*/
6655 static void
6656 gencjne (operand * left, operand * right, symbol * lbl)
6657 {
6658   symbol *tlbl = newiTempLabel (NULL);
6659
6660   D (emitcode (";", "gencjne"));
6661
6662   gencjneshort (left, right, lbl);
6663
6664   emitcode ("mov", "a,%s", one);
6665   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6666   emitLabel (lbl);
6667   emitcode ("clr", "a");
6668   emitLabel (tlbl);
6669 }
6670
6671 /*-----------------------------------------------------------------*/
6672 /* genCmpEq - generates code for equal to                          */
6673 /*-----------------------------------------------------------------*/
6674 static void
6675 genCmpEq (iCode * ic, iCode * ifx)
6676 {
6677   operand *left, *right, *result;
6678
6679   D (emitcode (";", "genCmpEq"));
6680
6681   AOP_OP_2 (ic);
6682   AOP_SET_LOCALS (ic);
6683
6684   /* if literal, literal on the right or
6685      if the right is in a pointer register and left
6686      is not */
6687   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6688       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6689     {
6690       operand *t = IC_RIGHT (ic);
6691       IC_RIGHT (ic) = IC_LEFT (ic);
6692       IC_LEFT (ic) = t;
6693     }
6694
6695   if (ifx &&                    /* !AOP_SIZE(result) */
6696       OP_SYMBOL (result) &&
6697       OP_SYMBOL (result)->regType == REG_CND)
6698     {
6699       symbol *tlbl;
6700       /* if they are both bit variables */
6701       if (AOP_TYPE (left) == AOP_CRY &&
6702           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6703         {
6704           if (AOP_TYPE (right) == AOP_LIT)
6705             {
6706               unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6707               if (lit == 0L)
6708                 {
6709                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6710                   emitcode ("cpl", "c");
6711                 }
6712               else if (lit == 1L)
6713                 {
6714                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6715                 }
6716               else
6717                 {
6718                   emitcode ("clr", "c");
6719                 }
6720               /* AOP_TYPE(right) == AOP_CRY */
6721             }
6722           else
6723             {
6724               symbol *lbl = newiTempLabel (NULL);
6725               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6726               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6727               emitcode ("cpl", "c");
6728               emitLabel (lbl);
6729             }
6730           /* if true label then we jump if condition
6731              supplied is true */
6732           tlbl = newiTempLabel (NULL);
6733           if (IC_TRUE (ifx))
6734             {
6735               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6736               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6737             }
6738           else
6739             {
6740               emitcode ("jc", "!tlabel", tlbl->key + 100);
6741               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6742             }
6743           emitLabel (tlbl);
6744         }
6745       else
6746         {
6747           tlbl = newiTempLabel (NULL);
6748           gencjneshort (left, right, tlbl);
6749           if (IC_TRUE (ifx))
6750             {
6751               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6752               emitLabel (tlbl);
6753             }
6754           else
6755             {
6756               symbol *lbl = newiTempLabel (NULL);
6757               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6758               emitLabel (tlbl);
6759               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6760               emitLabel (lbl);
6761             }
6762         }
6763       /* mark the icode as generated */
6764       ifx->generated = 1;
6765
6766       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6767       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6768       return;
6769     }
6770
6771   /* if they are both bit variables */
6772   if (AOP_TYPE (left) == AOP_CRY &&
6773       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6774     {
6775       if (AOP_TYPE (right) == AOP_LIT)
6776         {
6777           unsigned long lit = ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6778           if (lit == 0L)
6779             {
6780               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6781               emitcode ("cpl", "c");
6782             }
6783           else if (lit == 1L)
6784             {
6785               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6786             }
6787           else
6788             {
6789               emitcode ("clr", "c");
6790             }
6791           /* AOP_TYPE(right) == AOP_CRY */
6792         }
6793       else
6794         {
6795           symbol *lbl = newiTempLabel (NULL);
6796           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6797           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6798           emitcode ("cpl", "c");
6799           emitLabel (lbl);
6800         }
6801
6802       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6803       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6804
6805       aopOp (result, ic, TRUE, FALSE);
6806
6807       /* c = 1 if egal */
6808       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6809         {
6810           outBitC (result);
6811           goto release;
6812         }
6813       if (ifx)
6814         {
6815           genIfxJump (ifx, "c");
6816           goto release;
6817         }
6818       /* if the result is used in an arithmetic operation
6819          then put the result in place */
6820       outBitC (result);
6821     }
6822   else
6823     {
6824       gencjne (left, right, newiTempLabel (NULL));
6825
6826       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6827       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6828
6829       aopOp (result, ic, TRUE, FALSE);
6830
6831       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6832         {
6833           aopPut (result, "a", 0);
6834           goto release;
6835         }
6836       if (ifx)
6837         {
6838           genIfxJump (ifx, "a");
6839           goto release;
6840         }
6841       /* if the result is used in an arithmetic operation
6842          then put the result in place */
6843       if (AOP_TYPE (result) != AOP_CRY)
6844         outAcc (result);
6845       /* leave the result in acc */
6846     }
6847
6848 release:
6849   freeAsmop (result, NULL, ic, TRUE);
6850 }
6851
6852 /*-----------------------------------------------------------------*/
6853 /* ifxForOp - returns the icode containing the ifx for operand     */
6854 /*-----------------------------------------------------------------*/
6855 static iCode *
6856 ifxForOp (operand * op, iCode * ic)
6857 {
6858   /* if true symbol then needs to be assigned */
6859   if (IS_TRUE_SYMOP (op))
6860     return NULL;
6861
6862   /* if this has register type condition and
6863      the next instruction is ifx with the same operand
6864      and live to of the operand is upto the ifx only then */
6865   if (ic->next &&
6866       ic->next->op == IFX &&
6867       IC_COND (ic->next)->key == op->key &&
6868       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6869     return ic->next;
6870
6871   return NULL;
6872 }
6873
6874 /*-----------------------------------------------------------------*/
6875 /* hasInc - operand is incremented before any other use            */
6876 /*-----------------------------------------------------------------*/
6877 static iCode *
6878 hasInc (operand *op, iCode *ic, int osize)
6879 {
6880   sym_link *type = operandType(op);
6881   sym_link *retype = getSpec (type);
6882   iCode *lic = ic->next;
6883   int isize ;
6884
6885   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6886   if (!IS_SYMOP(op)) return NULL;
6887
6888   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6889   if (IS_AGGREGATE(type->next)) return NULL;
6890   if (osize != (isize = getSize(type->next))) return NULL;
6891
6892   while (lic) {
6893       /* if operand of the form op = op + <sizeof *op> */
6894       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6895           isOperandEqual(IC_RESULT(lic),op) &&
6896           isOperandLiteral(IC_RIGHT(lic)) &&
6897           operandLitValue(IC_RIGHT(lic)) == isize) {
6898           return lic;
6899       }
6900       /* if the operand used or deffed */
6901       if (bitVectBitValue(OP_USES(op),lic->key) || lic->defKey == op->key) {
6902           return NULL;
6903       }
6904       /* if GOTO or IFX */
6905       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6906       lic = lic->next;
6907   }
6908   return NULL;
6909 }
6910
6911 /*-----------------------------------------------------------------*/
6912 /* genAndOp - for && operation                                     */
6913 /*-----------------------------------------------------------------*/
6914 static void
6915 genAndOp (iCode * ic)
6916 {
6917   operand *left, *right, *result;
6918   symbol *tlbl;
6919
6920   D (emitcode (";", "genAndOp"));
6921
6922   /* note here that && operations that are in an
6923      if statement are taken away by backPatchLabels
6924      only those used in arthmetic operations remain */
6925   AOP_OP_2 (ic);
6926   AOP_SET_LOCALS (ic);
6927
6928   /* if both are bit variables */
6929   if (AOP_TYPE (left) == AOP_CRY &&
6930       AOP_TYPE (right) == AOP_CRY)
6931     {
6932       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6933       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6934       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6935       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6936
6937       aopOp (result,ic,FALSE, FALSE);
6938       outBitC (result);
6939     }
6940   else
6941     {
6942       tlbl = newiTempLabel (NULL);
6943       toBoolean (left);
6944       emitcode ("jz", "!tlabel", tlbl->key + 100);
6945       toBoolean (right);
6946       emitLabel (tlbl);
6947       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6948       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6949
6950       aopOp (result,ic,FALSE, FALSE);
6951       outBitAcc (result);
6952     }
6953
6954     freeAsmop (result, NULL, ic, TRUE);
6955 }
6956
6957
6958 /*-----------------------------------------------------------------*/
6959 /* genOrOp - for || operation                                      */
6960 /*-----------------------------------------------------------------*/
6961 static void
6962 genOrOp (iCode * ic)
6963 {
6964   operand *left, *right, *result;
6965   symbol *tlbl;
6966
6967   D (emitcode (";", "genOrOp"));
6968
6969   /* note here that || operations that are in an
6970      if statement are taken away by backPatchLabels
6971      only those used in arthmetic operations remain */
6972   AOP_OP_2 (ic);
6973   AOP_SET_LOCALS (ic);
6974
6975   /* if both are bit variables */
6976   if (AOP_TYPE (left) == AOP_CRY &&
6977       AOP_TYPE (right) == AOP_CRY)
6978     {
6979       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6980       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6981       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6982       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6983
6984       aopOp (result,ic,FALSE, FALSE);
6985
6986       outBitC (result);
6987     }
6988   else
6989     {
6990       tlbl = newiTempLabel (NULL);
6991       toBoolean (left);
6992       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6993       toBoolean (right);
6994       emitLabel (tlbl);
6995       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6996       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6997
6998       aopOp (result,ic,FALSE, FALSE);
6999
7000       outBitAcc (result);
7001     }
7002
7003   freeAsmop (result, NULL, ic, TRUE);
7004 }
7005
7006 /*-----------------------------------------------------------------*/
7007 /* isLiteralBit - test if lit == 2^n                               */
7008 /*-----------------------------------------------------------------*/
7009 static int
7010 isLiteralBit (unsigned long lit)
7011 {
7012   unsigned long pw[32] =
7013   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
7014    0x100L, 0x200L, 0x400L, 0x800L,
7015    0x1000L, 0x2000L, 0x4000L, 0x8000L,
7016    0x10000L, 0x20000L, 0x40000L, 0x80000L,
7017    0x100000L, 0x200000L, 0x400000L, 0x800000L,
7018    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
7019    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
7020   int idx;
7021
7022   for (idx = 0; idx < 32; idx++)
7023     if (lit == pw[idx])
7024       return idx + 1;
7025   return 0;
7026 }
7027
7028 /*-----------------------------------------------------------------*/
7029 /* continueIfTrue -                                                */
7030 /*-----------------------------------------------------------------*/
7031 static void
7032 continueIfTrue (iCode * ic)
7033 {
7034   if (IC_TRUE (ic))
7035     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7036   ic->generated = 1;
7037 }
7038
7039 /*-----------------------------------------------------------------*/
7040 /* jmpIfTrue -                                                     */
7041 /*-----------------------------------------------------------------*/
7042 static void
7043 jumpIfTrue (iCode * ic)
7044 {
7045   if (!IC_TRUE (ic))
7046     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7047   ic->generated = 1;
7048 }
7049
7050 /*-----------------------------------------------------------------*/
7051 /* jmpTrueOrFalse -                                                */
7052 /*-----------------------------------------------------------------*/
7053 static void
7054 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
7055 {
7056   // ugly but optimized by peephole
7057   if (IC_TRUE (ic))
7058     {
7059       symbol *nlbl = newiTempLabel (NULL);
7060       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
7061       emitLabel (tlbl);
7062       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
7063       emitLabel (nlbl);
7064     }
7065   else
7066     {
7067       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
7068       emitLabel (tlbl);
7069     }
7070   ic->generated = 1;
7071 }
7072
7073 // Generate code to perform a bit-wise logic operation
7074 // on two operands in far space (assumed to already have been
7075 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
7076 // in far space. This requires pushing the result on the stack
7077 // then popping it into the result.
7078 static void
7079 genFarFarLogicOp(iCode *ic, char *logicOp)
7080 {
7081       int size, resultSize, compSize;
7082       int offset = 0;
7083
7084       TR_AP("#5");
7085       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
7086       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
7087                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
7088
7089       _startLazyDPSEvaluation();
7090       for (size = compSize; (size--); offset++)
7091       {
7092           MOVA (aopGet (IC_LEFT(ic), offset, FALSE, FALSE, NULL));
7093           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
7094           MOVA (aopGet (IC_RIGHT(ic), offset, FALSE, FALSE, NULL));
7095
7096           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
7097           emitcode ("push", "acc");
7098       }
7099       _endLazyDPSEvaluation();
7100
7101       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7102       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
7103       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
7104
7105       resultSize = AOP_SIZE(IC_RESULT(ic));
7106
7107       ADJUST_PUSHED_RESULT(compSize, resultSize);
7108
7109       _startLazyDPSEvaluation();
7110       while (compSize--)
7111       {
7112           emitcode ("pop", "acc");
7113           aopPut (IC_RESULT (ic), "a", compSize);
7114       }
7115       _endLazyDPSEvaluation();
7116       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
7117 }
7118
7119
7120 /*-----------------------------------------------------------------*/
7121 /* genAnd  - code for and                                          */
7122 /*-----------------------------------------------------------------*/
7123 static void
7124 genAnd (iCode * ic, iCode * ifx)
7125 {
7126   operand *left, *right, *result;
7127   int size, offset = 0;
7128   unsigned long lit = 0L;
7129   int bytelit = 0;
7130   char buffer[10];
7131   bool pushResult;
7132
7133   D (emitcode (";", "genAnd"));
7134
7135   AOP_OP_3_NOFATAL (ic, pushResult);
7136   AOP_SET_LOCALS (ic);
7137
7138   if (pushResult)
7139   {
7140       genFarFarLogicOp(ic, "anl");
7141       return;
7142   }
7143
7144 #ifdef DEBUG_TYPE
7145   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7146             AOP_TYPE (result),
7147             AOP_TYPE (left), AOP_TYPE (right));
7148   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7149             AOP_SIZE (result),
7150             AOP_SIZE (left), AOP_SIZE (right));
7151 #endif
7152
7153   /* if left is a literal & right is not then exchange them */
7154   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7155 #ifdef LOGIC_OPS_BROKEN
7156     ||  AOP_NEEDSACC (left)
7157 #endif
7158     )
7159     {
7160       operand *tmp = right;
7161       right = left;
7162       left = tmp;
7163     }
7164
7165   /* if result = right then exchange left and right */
7166   if (sameRegs (AOP (result), AOP (right)))
7167     {
7168       operand *tmp = right;
7169       right = left;
7170       left = tmp;
7171     }
7172
7173   /* if right is bit then exchange them */
7174   if (AOP_TYPE (right) == AOP_CRY &&
7175       AOP_TYPE (left) != AOP_CRY)
7176     {
7177       operand *tmp = right;
7178       right = left;
7179       left = tmp;
7180     }
7181   if (AOP_TYPE (right) == AOP_LIT)
7182     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7183
7184   size = AOP_SIZE (result);
7185
7186   // if(bit & yy)
7187   // result = bit & yy;
7188   if (AOP_TYPE (left) == AOP_CRY)
7189     {
7190       // c = bit & literal;
7191       if (AOP_TYPE (right) == AOP_LIT)
7192         {
7193           if (lit & 1)
7194             {
7195               if (size && sameRegs (AOP (result), AOP (left)))
7196                 // no change
7197                 goto release;
7198               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7199             }
7200           else
7201             {
7202               // bit(result) = 0;
7203               if (size && (AOP_TYPE (result) == AOP_CRY))
7204                 {
7205                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
7206                   goto release;
7207                 }
7208               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7209                 {
7210                   jumpIfTrue (ifx);
7211                   goto release;
7212                 }
7213               emitcode ("clr", "c");
7214             }
7215         }
7216       else
7217         {
7218           if (AOP_TYPE (right) == AOP_CRY)
7219             {
7220               // c = bit & bit;
7221               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7222               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7223             }
7224           else
7225             {
7226               // c = bit & val;
7227               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
7228               // c = lsb
7229               emitcode ("rrc", "a");
7230               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
7231             }
7232         }
7233       // bit = c
7234       // val = c
7235       if (size)
7236         outBitC (result);
7237       // if(bit & ...)
7238       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7239         genIfxJump (ifx, "c");
7240       goto release;
7241     }
7242
7243   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
7244   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
7245   if ((AOP_TYPE (right) == AOP_LIT) &&
7246       (AOP_TYPE (result) == AOP_CRY) &&
7247       (AOP_TYPE (left) != AOP_CRY))
7248     {
7249       int posbit = isLiteralBit (lit);
7250       /* left &  2^n */
7251       if (posbit)
7252         {
7253           posbit--;
7254           MOVA (aopGet (left, posbit >> 3, FALSE, FALSE, NULL));
7255           // bit = left & 2^n
7256           if (size)
7257             {
7258               switch (posbit & 0x07)
7259                 {
7260                   case 0: emitcode ("rrc", "a");
7261                           break;
7262                   case 7: emitcode ("rlc", "a");
7263                           break;
7264                   default: emitcode ("mov", "c,acc.%d", posbit & 0x07);
7265                           break;
7266                 }
7267             }
7268           // if(left &  2^n)
7269           else
7270             {
7271               if (ifx)
7272                 {
7273                   SNPRINTF (buffer, sizeof(buffer),
7274                             "acc.%d", posbit & 0x07);
7275                   genIfxJump (ifx, buffer);
7276                 }
7277               else
7278                 {
7279                   emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
7280                 }
7281               goto release;
7282             }
7283         }
7284       else
7285         {
7286           symbol *tlbl = newiTempLabel (NULL);
7287           int sizel = AOP_SIZE (left);
7288           if (size)
7289             emitcode ("setb", "c");
7290           while (sizel--)
7291             {
7292               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
7293                 {
7294                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7295                   // byte ==  2^n ?
7296                   if ((posbit = isLiteralBit (bytelit)) != 0)
7297                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
7298                   else
7299                     {
7300                       if (bytelit != 0x0FFL)
7301                         emitcode ("anl", "a,%s",
7302                           aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7303                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
7304                     }
7305                 }
7306               offset++;
7307             }
7308           // bit = left & literal
7309           if (size)
7310             {
7311               emitcode ("clr", "c");
7312               emitLabel (tlbl);
7313             }
7314           // if(left & literal)
7315           else
7316             {
7317               if (ifx)
7318                 jmpTrueOrFalse (ifx, tlbl);
7319               else
7320                 emitLabel (tlbl);
7321               goto release;
7322             }
7323         }
7324       outBitC (result);
7325       goto release;
7326     }
7327
7328   /* if left is same as result */
7329   if (sameRegs (AOP (result), AOP (left)))
7330     {
7331       for (; size--; offset++)
7332         {
7333           if (AOP_TYPE (right) == AOP_LIT)
7334             {
7335               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7336               if (bytelit == 0x0FF)
7337                 {
7338                   /* dummy read of volatile operand */
7339                   if (isOperandVolatile (left, FALSE))
7340                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7341                   else
7342                     continue;
7343                 }
7344               else if (bytelit == 0)
7345                 {
7346                   aopPut (result, zero, offset);
7347                 }
7348               else if (IS_AOP_PREG (result))
7349                 {
7350                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7351                   emitcode ("anl", "a,%s",
7352                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
7353                   aopPut (result, "a", offset);
7354                 }
7355               else
7356                 emitcode ("anl", "%s,%s",
7357                           aopGet (left, offset, FALSE, TRUE, NULL),
7358                           aopGet (right, offset, FALSE, FALSE, NULL));
7359             }
7360           else
7361             {
7362               if (AOP_TYPE (left) == AOP_ACC)
7363                 {
7364                   if (offset)
7365                     emitcode("mov", "a,b");
7366                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7367                 }
7368               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7369                 {
7370                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7371                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7372                   emitcode ("anl", "a,b");
7373                   aopPut (result, "a", offset);
7374                 }
7375               else if (aopGetUsesAcc (left, offset))
7376                 {
7377                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7378                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7379                   aopPut (result, "a", offset);
7380                 }
7381               else
7382                 {
7383                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7384                   if (IS_AOP_PREG (result))
7385                     {
7386                       emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7387                       aopPut (result, "a", offset);
7388                     }
7389                   else
7390                     emitcode ("anl", "%s,a", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7391                 }
7392             }
7393         }
7394     }
7395   else
7396     {
7397       // left & result in different registers
7398       if (AOP_TYPE (result) == AOP_CRY)
7399         {
7400           // result = bit
7401           // if(size), result in bit
7402           // if(!size && ifx), conditional oper: if(left & right)
7403           symbol *tlbl = newiTempLabel (NULL);
7404           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
7405           if (size)
7406             emitcode ("setb", "c");
7407           while (sizer--)
7408             {
7409               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7410                   && AOP_TYPE(left)==AOP_ACC)
7411                 {
7412                   if (offset)
7413                     emitcode("mov", "a,b");
7414                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7415                 }
7416               else if (AOP_TYPE(left)==AOP_ACC)
7417                 {
7418                   if (!offset)
7419                     {
7420                       bool pushedB = pushB ();
7421                       emitcode("mov", "b,a");
7422                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7423                       emitcode("anl", "a,b");
7424                       popB (pushedB);
7425                     }
7426                   else
7427                     {
7428                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7429                       emitcode("anl", "a,b");
7430                     }
7431                 }
7432               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7433                 {
7434                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7435                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7436                   emitcode ("anl", "a,b");
7437                 }
7438               else if (aopGetUsesAcc (left, offset))
7439                 {
7440                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7441                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7442                 }
7443               else
7444                 {
7445                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7446                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7447                 }
7448
7449               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7450               offset++;
7451             }
7452           if (size)
7453             {
7454               CLRC;
7455               emitLabel (tlbl);
7456               outBitC (result);
7457             }
7458           else if (ifx)
7459             jmpTrueOrFalse (ifx, tlbl);
7460           else
7461             emitLabel (tlbl);
7462         }
7463       else
7464         {
7465           for (; (size--); offset++)
7466             {
7467               // normal case
7468               // result = left & right
7469               if (AOP_TYPE (right) == AOP_LIT)
7470                 {
7471                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7472                   if (bytelit == 0x0FF)
7473                     {
7474                       aopPut (result,
7475                               aopGet (left, offset, FALSE, FALSE, NULL),
7476                               offset);
7477                       continue;
7478                     }
7479                   else if (bytelit == 0)
7480                     {
7481                       /* dummy read of volatile operand */
7482                       if (isOperandVolatile (left, FALSE))
7483                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7484                       aopPut (result, zero, offset);
7485                       continue;
7486                     }
7487                   else if (AOP_TYPE (left) == AOP_ACC)
7488                     {
7489                       if (!offset)
7490                         {
7491                           emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7492                           aopPut (result, "a", offset);
7493                           continue;
7494                         }
7495                       else
7496                         {
7497                           emitcode ("anl", "b,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7498                           aopPut (result, "b", offset);
7499                           continue;
7500                         }
7501                     }
7502                 }
7503               // faster than result <- left, anl result,right
7504               // and better if result is SFR
7505               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7506                   && AOP_TYPE(left)==AOP_ACC)
7507                 {
7508                   if (offset)
7509                     emitcode("mov", "a,b");
7510                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, NULL));
7511                 }
7512               else if (AOP_TYPE(left)==AOP_ACC)
7513                 {
7514                   if (!offset)
7515                     {
7516                       bool pushedB = pushB ();
7517                       emitcode("mov", "b,a");
7518                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7519                       emitcode("anl", "a,b");
7520                       popB (pushedB);
7521                     }
7522                   else
7523                     {
7524                       MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7525                       emitcode("anl", "a,b");
7526                     }
7527                 }
7528               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7529                 {
7530                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7531                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7532                   emitcode ("anl", "a,b");
7533                 }
7534               else if (aopGetUsesAcc (left, offset))
7535                 {
7536                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7537                   emitcode ("anl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7538                 }
7539               else
7540                 {
7541                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7542                   emitcode ("anl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7543                 }
7544               aopPut (result, "a", offset);
7545             }
7546         }
7547     }
7548
7549 release:
7550   freeAsmop (result, NULL, ic, TRUE);
7551   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7552   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7553 }
7554
7555 /*-----------------------------------------------------------------*/
7556 /* genOr  - code for or                                            */
7557 /*-----------------------------------------------------------------*/
7558 static void
7559 genOr (iCode * ic, iCode * ifx)
7560 {
7561   operand *left, *right, *result;
7562   int size, offset = 0;
7563   unsigned long lit = 0L;
7564   int bytelit = 0;
7565   bool     pushResult;
7566
7567   D (emitcode (";", "genOr"));
7568
7569   AOP_OP_3_NOFATAL (ic, pushResult);
7570   AOP_SET_LOCALS (ic);
7571
7572   if (pushResult)
7573   {
7574       genFarFarLogicOp(ic, "orl");
7575       return;
7576   }
7577
7578
7579 #ifdef DEBUG_TYPE
7580   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7581             AOP_TYPE (result),
7582             AOP_TYPE (left), AOP_TYPE (right));
7583   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7584             AOP_SIZE (result),
7585             AOP_SIZE (left), AOP_SIZE (right));
7586 #endif
7587
7588   /* if left is a literal & right is not then exchange them */
7589   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7590 #ifdef LOGIC_OPS_BROKEN
7591    || AOP_NEEDSACC (left) // I think this is a net loss now.
7592 #endif
7593       )
7594     {
7595       operand *tmp = right;
7596       right = left;
7597       left = tmp;
7598     }
7599
7600   /* if result = right then exchange them */
7601   if (sameRegs (AOP (result), AOP (right)))
7602     {
7603       operand *tmp = right;
7604       right = left;
7605       left = tmp;
7606     }
7607
7608   /* if right is bit then exchange them */
7609   if (AOP_TYPE (right) == AOP_CRY &&
7610       AOP_TYPE (left) != AOP_CRY)
7611     {
7612       operand *tmp = right;
7613       right = left;
7614       left = tmp;
7615     }
7616   if (AOP_TYPE (right) == AOP_LIT)
7617     lit = ulFromVal (AOP (right)->aopu.aop_lit);
7618
7619   size = AOP_SIZE (result);
7620
7621   // if(bit | yy)
7622   // xx = bit | yy;
7623   if (AOP_TYPE (left) == AOP_CRY)
7624     {
7625       if (AOP_TYPE (right) == AOP_LIT)
7626         {
7627           // c = bit | literal;
7628           if (lit)
7629             {
7630               // lit != 0 => result = 1
7631               if (AOP_TYPE (result) == AOP_CRY)
7632                 {
7633                   if (size)
7634                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7635                   else if (ifx)
7636                     continueIfTrue (ifx);
7637                   goto release;
7638                 }
7639               emitcode ("setb", "c");
7640             }
7641           else
7642             {
7643               // lit == 0 => result = left
7644               if (size && sameRegs (AOP (result), AOP (left)))
7645                 goto release;
7646               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7647             }
7648         }
7649       else
7650         {
7651           if (AOP_TYPE (right) == AOP_CRY)
7652             {
7653               // c = bit | bit;
7654               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7655               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7656             }
7657           else
7658             {
7659               // c = bit | val;
7660               symbol *tlbl = newiTempLabel (NULL);
7661               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7662                 emitcode ("setb", "c");
7663               emitcode ("jb", "%s,!tlabel",
7664                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7665               toBoolean (right);
7666               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7667               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7668                 {
7669                   jmpTrueOrFalse (ifx, tlbl);
7670                   goto release;
7671                 }
7672               else
7673                 {
7674                   CLRC;
7675                   emitLabel (tlbl);
7676                 }
7677             }
7678         }
7679       // bit = c
7680       // val = c
7681       if (size)
7682         outBitC (result);
7683       // if(bit | ...)
7684       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7685            genIfxJump (ifx, "c");
7686       goto release;
7687     }
7688
7689   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7690   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7691   if ((AOP_TYPE (right) == AOP_LIT) &&
7692       (AOP_TYPE (result) == AOP_CRY) &&
7693       (AOP_TYPE (left) != AOP_CRY))
7694     {
7695       if (lit)
7696         {
7697           // result = 1
7698           if (size)
7699             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7700           else
7701             continueIfTrue (ifx);
7702           goto release;
7703         }
7704       else
7705         {
7706           // lit = 0, result = boolean(left)
7707           if (size)
7708             emitcode ("setb", "c");
7709           toBoolean (right);
7710           if (size)
7711             {
7712               symbol *tlbl = newiTempLabel (NULL);
7713               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7714               CLRC;
7715               emitLabel (tlbl);
7716             }
7717           else
7718             {
7719               genIfxJump (ifx, "a");
7720               goto release;
7721             }
7722         }
7723       outBitC (result);
7724       goto release;
7725     }
7726
7727   /* if left is same as result */
7728   if (sameRegs (AOP (result), AOP (left)))
7729     {
7730       for (; size--; offset++)
7731         {
7732           if (AOP_TYPE (right) == AOP_LIT)
7733             {
7734               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7735               if (bytelit == 0)
7736                 {
7737                   /* dummy read of volatile operand */
7738                   if (isOperandVolatile (left, FALSE))
7739                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7740                   else
7741                     continue;
7742                 }
7743               else if (bytelit == 0x0FF)
7744                 {
7745                   aopPut (result, "#0xFF", offset);
7746                 }
7747               else if (IS_AOP_PREG (left))
7748                 {
7749                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7750                   emitcode ("orl", "a,%s",
7751                             aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7752                   aopPut (result, "a", offset);
7753                 }
7754               else
7755                 {
7756                   emitcode ("orl", "%s,%s",
7757                             aopGet (left, offset, FALSE, TRUE, NULL),
7758                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7759                 }
7760             }
7761           else
7762             {
7763               if (AOP_TYPE (left) == AOP_ACC)
7764                 {
7765                   if (offset)
7766                     emitcode("mov", "a,b");
7767                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7768                 }
7769               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7770                 {
7771                   emitcode ("mov", "b,%s", aopGet (left, offset, FALSE, FALSE, NULL));
7772                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7773                   emitcode ("orl", "a,b");
7774                   aopPut (result, "a", offset);
7775                 }
7776               else if (aopGetUsesAcc (left, offset))
7777                 {
7778                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7779                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7780                   aopPut (result, "a", offset);
7781                 }
7782               else
7783                 {
7784                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7785                   if (IS_AOP_PREG (left))
7786                     {
7787                       emitcode ("orl", "a,%s",
7788                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7789                       aopPut (result, "a", offset);
7790                     }
7791                   else
7792                     {
7793                       emitcode ("orl", "%s,a",
7794                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
7795                     }
7796                 }
7797             }
7798         }
7799     }
7800   else
7801     {
7802       // left & result in different registers
7803       if (AOP_TYPE (result) == AOP_CRY)
7804         {
7805           // result = bit
7806           // if(size), result in bit
7807           // if(!size && ifx), conditional oper: if(left | right)
7808           symbol *tlbl = newiTempLabel (NULL);
7809           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7810           if (size)
7811             emitcode ("setb", "c");
7812           while (sizer--)
7813             {
7814               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7815                   && AOP_TYPE(left)==AOP_ACC)
7816                 {
7817                   if (offset)
7818                     emitcode("mov", "a,b");
7819                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7820                 }
7821               else if (AOP_TYPE(left)==AOP_ACC)
7822                 {
7823                   if (!offset)
7824                     {
7825                       bool pushedB = pushB ();
7826                       emitcode("mov", "b,a");
7827                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7828                       emitcode("orl", "a,b");
7829                       popB (pushedB);
7830                     }
7831                   else
7832                     {
7833                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7834                       emitcode("orl", "a,b");
7835                     }
7836                 }
7837               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7838                 {
7839                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7840                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7841                   emitcode ("orl", "a,b");
7842                 }
7843               else if (aopGetUsesAcc (left, offset))
7844                 {
7845                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7846                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7847                 }
7848               else
7849                 {
7850                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7851                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7852               }
7853
7854               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7855               offset++;
7856             }
7857           if (size)
7858             {
7859               CLRC;
7860               emitLabel (tlbl);
7861               outBitC (result);
7862             }
7863           else if (ifx)
7864             jmpTrueOrFalse (ifx, tlbl);
7865           else
7866             emitLabel (tlbl);
7867         }
7868       else
7869         {
7870             _startLazyDPSEvaluation();
7871           for (; (size--); offset++)
7872             {
7873               // normal case
7874               // result = left | right
7875               if (AOP_TYPE (right) == AOP_LIT)
7876                 {
7877                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7878                   if (bytelit == 0)
7879                     {
7880                       aopPut (result,
7881                               aopGet (left, offset, FALSE, FALSE, NULL),
7882                               offset);
7883                       continue;
7884                     }
7885                   else if (bytelit == 0x0FF)
7886                     {
7887                       /* dummy read of volatile operand */
7888                       if (isOperandVolatile (left, FALSE))
7889                         MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7890                       aopPut (result, "#0xFF", offset);
7891                       continue;
7892                     }
7893                 }
7894               // faster than result <- left, orl result,right
7895               // and better if result is SFR
7896               if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
7897                   && AOP_TYPE(left)==AOP_ACC)
7898                 {
7899                   if (offset)
7900                     emitcode("mov", "a,b");
7901                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7902                 }
7903               else if (AOP_TYPE(left)==AOP_ACC)
7904                 {
7905                   if (!offset)
7906                     {
7907                       bool pushedB = pushB ();
7908                       emitcode("mov", "b,a");
7909                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7910                       emitcode("orl", "a,b");
7911                       popB (pushedB);
7912                     }
7913                   else
7914                     {
7915                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7916                       emitcode("orl", "a,b");
7917                     }
7918                 }
7919               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
7920                 {
7921                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
7922                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7923                   emitcode ("orl", "a,b");
7924                 }
7925               else if (aopGetUsesAcc (left, offset))
7926                 {
7927                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
7928                   emitcode ("orl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
7929                 }
7930               else
7931                 {
7932                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
7933                   emitcode ("orl", "a,%s", aopGet (left, offset, FALSE, FALSE, DP2_RESULT_REG));
7934                 }
7935               aopPut (result, "a", offset);
7936             }
7937             _endLazyDPSEvaluation();
7938         }
7939     }
7940
7941 release:
7942   freeAsmop (result, NULL, ic, TRUE);
7943   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7944   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7945 }
7946
7947 /*-----------------------------------------------------------------*/
7948 /* genXor - code for xclusive or                                   */
7949 /*-----------------------------------------------------------------*/
7950 static void
7951 genXor (iCode * ic, iCode * ifx)
7952 {
7953   operand *left, *right, *result;
7954   int size, offset = 0;
7955   unsigned long lit = 0L;
7956   int bytelit = 0;
7957   bool pushResult;
7958
7959   D (emitcode (";", "genXor"));
7960
7961   AOP_OP_3_NOFATAL (ic, pushResult);
7962   AOP_SET_LOCALS (ic);
7963
7964   if (pushResult)
7965   {
7966       genFarFarLogicOp(ic, "xrl");
7967       return;
7968   }
7969
7970 #ifdef DEBUG_TYPE
7971   emitcode (";", "Type res[%d] = l[%d]&r[%d]",
7972             AOP_TYPE (result),
7973             AOP_TYPE (left), AOP_TYPE (right));
7974   emitcode (";", "Size res[%d] = l[%d]&r[%d]",
7975             AOP_SIZE (result),
7976             AOP_SIZE (left), AOP_SIZE (right));
7977 #endif
7978
7979   /* if left is a literal & right is not ||
7980      if left needs acc & right does not */
7981   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7982 #ifdef LOGIC_OPS_BROKEN
7983       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7984 #endif
7985      )
7986     {
7987       operand *tmp = right;
7988       right = left;
7989       left = tmp;
7990     }
7991
7992   /* if result = right then exchange them */
7993   if (sameRegs (AOP (result), AOP (right)))
7994     {
7995       operand *tmp = right;
7996       right = left;
7997       left = tmp;
7998     }
7999
8000   /* if right is bit then exchange them */
8001   if (AOP_TYPE (right) == AOP_CRY &&
8002       AOP_TYPE (left) != AOP_CRY)
8003     {
8004       operand *tmp = right;
8005       right = left;
8006       left = tmp;
8007     }
8008   if (AOP_TYPE (right) == AOP_LIT)
8009     lit = ulFromVal (AOP (right)->aopu.aop_lit);
8010
8011   size = AOP_SIZE (result);
8012
8013   // if(bit ^ yy)
8014   // xx = bit ^ yy;
8015   if (AOP_TYPE (left) == AOP_CRY)
8016     {
8017       if (AOP_TYPE (right) == AOP_LIT)
8018         {
8019           // c = bit & literal;
8020           if (lit >> 1)
8021             {
8022               // lit>>1  != 0 => result = 1
8023               if (AOP_TYPE (result) == AOP_CRY)
8024                 {
8025                   if (size)
8026                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
8027                   else if (ifx)
8028                     continueIfTrue (ifx);
8029                   goto release;
8030                 }
8031               emitcode ("setb", "c");
8032             }
8033           else
8034             {
8035               // lit == (0 or 1)
8036               if (lit == 0)
8037                 {
8038                   // lit == 0, result = left
8039                   if (size && sameRegs (AOP (result), AOP (left)))
8040                     goto release;
8041                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8042                 }
8043               else
8044                 {
8045                   // lit == 1, result = not(left)
8046                   if (size && sameRegs (AOP (result), AOP (left)))
8047                     {
8048                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
8049                       goto release;
8050                     }
8051                   else
8052                     {
8053                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
8054                       emitcode ("cpl", "c");
8055                     }
8056                 }
8057             }
8058         }
8059       else
8060         {
8061           // right != literal
8062           symbol *tlbl = newiTempLabel (NULL);
8063           if (AOP_TYPE (right) == AOP_CRY)
8064             {
8065               // c = bit ^ bit;
8066               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
8067             }
8068           else
8069             {
8070               int sizer = AOP_SIZE (right);
8071               // c = bit ^ val
8072               // if val>>1 != 0, result = 1
8073               emitcode ("setb", "c");
8074               while (sizer)
8075                 {
8076                   MOVA (aopGet (right, sizer - 1, FALSE, FALSE, NULL));
8077                   if (sizer == 1)
8078                     // test the msb of the lsb
8079                     emitcode ("anl", "a,#!constbyte",0xfe);
8080                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
8081                   sizer--;
8082                 }
8083               // val = (0,1)
8084               emitcode ("rrc", "a");
8085             }
8086           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
8087           emitcode ("cpl", "c");
8088           emitLabel (tlbl);
8089         }
8090       // bit = c
8091       // val = c
8092       if (size)
8093         outBitC (result);
8094       // if(bit | ...)
8095       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
8096         genIfxJump (ifx, "c");
8097       goto release;
8098     }
8099
8100   /* if left is same as result */
8101   if (sameRegs (AOP (result), AOP (left)))
8102     {
8103       for (; size--; offset++)
8104         {
8105           if (AOP_TYPE (right) == AOP_LIT)
8106             {
8107               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8108               if (bytelit == 0)
8109                 {
8110                   /* dummy read of volatile operand */
8111                   if (isOperandVolatile (left, FALSE))
8112                     MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8113                   else
8114                     continue;
8115                 }
8116               else if (IS_AOP_PREG (left))
8117                 {
8118                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8119                   emitcode ("xrl", "a,%s",
8120                             aopGet (right, offset, FALSE, TRUE, DP2_RESULT_REG));
8121                   aopPut (result, "a", offset);
8122                 }
8123               else
8124                 {
8125                   emitcode ("xrl", "%s,%s",
8126                             aopGet (left, offset, FALSE, TRUE, NULL),
8127                             aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8128                 }
8129             }
8130           else
8131             {
8132               if (AOP_TYPE (left) == AOP_ACC)
8133                 {
8134                   if (offset)
8135                     emitcode("mov", "a,b");
8136                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8137                 }
8138               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8139                 {
8140                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8141                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8142                   emitcode ("xrl", "a,b");
8143                   aopPut (result, "a", offset);
8144                 }
8145               else if (aopGetUsesAcc (left, offset))
8146                 {
8147                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8148                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8149                   aopPut (result, "a", offset);
8150                 }
8151               else
8152                 {
8153                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8154                   if (IS_AOP_PREG (left))
8155                     {
8156                       emitcode ("xrl", "a,%s",
8157                                 aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8158                       aopPut (result, "a", offset);
8159                     }
8160                   else
8161                     emitcode ("xrl", "%s,a",
8162                            aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8163                 }
8164             }
8165         }
8166     }
8167   else
8168     {
8169       // left & result in different registers
8170       if (AOP_TYPE (result) == AOP_CRY)
8171         {
8172           // result = bit
8173           // if(size), result in bit
8174           // if(!size && ifx), conditional oper: if(left ^ right)
8175           symbol *tlbl = newiTempLabel (NULL);
8176           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
8177
8178           if (size)
8179             emitcode ("setb", "c");
8180           while (sizer--)
8181             {
8182               if ((AOP_TYPE (right) == AOP_LIT) &&
8183                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
8184                 {
8185                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8186                 }
8187               else if ((AOP_TYPE(right)==AOP_REG  || IS_AOP_PREG(right) || AOP_TYPE(right)==AOP_DIR)
8188                   && AOP_TYPE(left)==AOP_ACC)
8189                 {
8190                   if (offset)
8191                     emitcode("mov", "a,b");
8192                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8193                 }
8194               else if (AOP_TYPE(left)==AOP_ACC)
8195                 {
8196                   if (!offset)
8197                     {
8198                       bool pushedB = pushB ();
8199                       emitcode("mov", "b,a");
8200                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8201                       emitcode("xrl", "a,b");
8202                       popB (pushedB);
8203                     }
8204                   else
8205                     {
8206                       MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8207                       emitcode("xrl", "a,b");
8208                     }
8209                 }
8210               else if (aopGetUsesAcc (left, offset) && aopGetUsesAcc (right, offset))
8211                 {
8212                   MOVB (aopGet (left, offset, FALSE, FALSE, NULL));
8213                   MOVA (aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8214                   emitcode ("xrl", "a,b");
8215                 }
8216               else if (aopGetUsesAcc (left, offset))
8217                 {
8218                   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8219                   emitcode ("xrl", "a,%s", aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8220                 }
8221               else
8222                 {
8223                   MOVA (aopGet (right, offset, FALSE, FALSE, NULL));
8224                   emitcode ("xrl", "a,%s", aopGet (left, offset, FALSE, TRUE, DP2_RESULT_REG));
8225                 }
8226
8227               emitcode ("jnz", "!tlabel", tlbl->key + 100);
8228               offset++;
8229             }
8230           if (size)
8231             {
8232               CLRC;
8233               emitLabel (tlbl);
8234               outBitC (result);
8235             }
8236           else if (ifx)
8237             jmpTrueOrFalse (ifx, tlbl);
8238         }
8239       else
8240         {
8241         for (; (size--); offset++)
8242           {
8243             // normal case
8244             // result = left ^ right
8245             if (AOP_TYPE (right) == AOP_LIT)
8246               {
8247                 bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
8248                 if (bytelit == 0)
8249                   {
8250                     aopPut (result,
8251                             aopGet (left, offset, FALSE, FALSE, NULL),
8252                             offset);
8253                     continue;
8254                   }
8255                 D (emitcode (";", "better literal XOR."));
8256                 MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8257                 emitcode ("xrl", "a, %s",
8258                           aopGet (right, offset, FALSE, FALSE, DP2_RESULT_REG));
8259               }
8260             else
8261               {
8262                 // faster than result <- left, anl result,right
8263                 // and better if result is SFR
8264                 if (AOP_TYPE (left) == AOP_ACC)
8265                   {
8266                     emitcode ("xrl", "a,%s",
8267                               aopGet (right, offset,
8268                                       FALSE, FALSE, DP2_RESULT_REG));
8269                   }
8270                 else
8271                   {
8272                       char *rOp = aopGet (right, offset, FALSE, FALSE, NULL);
8273                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
8274                       {
8275                           emitcode("mov", "b,a");
8276                           rOp = "b";
8277                       }
8278
8279                       MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
8280                       emitcode ("xrl", "a,%s", rOp);
8281                   }
8282               }
8283             aopPut (result, "a", offset);
8284           }
8285         }
8286     }
8287
8288 release:
8289   freeAsmop (result, NULL, ic, TRUE);
8290   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8291   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
8292 }
8293
8294 /*-----------------------------------------------------------------*/
8295 /* genInline - write the inline code out                           */
8296 /*-----------------------------------------------------------------*/
8297 static void
8298 genInline (iCode * ic)
8299 {
8300   char *buffer, *bp, *bp1;
8301   bool inComment = FALSE;
8302
8303   D (emitcode (";", "genInline"));
8304
8305   _G.inLine += (!options.asmpeep);
8306
8307   buffer = bp = bp1 = Safe_strdup (IC_INLINE(ic));
8308
8309   /* emit each line as a code */
8310   while (*bp)
8311     {
8312       switch (*bp)
8313         {
8314         case ';':
8315           inComment = TRUE;
8316           ++bp;
8317           break;
8318
8319         case '\n':
8320           inComment = FALSE;
8321           *bp++ = '\0';
8322           emitcode (bp1, "");
8323           bp1 = bp;
8324           break;
8325
8326         default:
8327           /* Add \n for labels, not dirs such as c:\mydir */
8328           if (!inComment && (*bp == ':') && (isspace((unsigned char)bp[1])))
8329             {
8330               ++bp;
8331               *bp = '\0';
8332               ++bp;
8333               emitcode (bp1, "");
8334               bp1 = bp;
8335             }
8336           else
8337             ++bp;
8338           break;
8339         }
8340     }
8341   if (bp1 != bp)
8342     emitcode (bp1, "");
8343
8344   Safe_free (buffer);
8345
8346   _G.inLine -= (!options.asmpeep);
8347 }
8348
8349 /*-----------------------------------------------------------------*/
8350 /* genRRC - rotate right with carry                                */
8351 /*-----------------------------------------------------------------*/
8352 static void
8353 genRRC (iCode * ic)
8354 {
8355   operand *left, *result;
8356   int     size, offset;
8357   char *l;
8358
8359   D (emitcode (";", "genRRC"));
8360
8361   /* rotate right with carry */
8362   left = IC_LEFT (ic);
8363   result = IC_RESULT (ic);
8364   aopOp (left, ic, FALSE, FALSE);
8365   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8366
8367   /* move it to the result */
8368   size = AOP_SIZE (result);
8369   offset = size - 1;
8370   CLRC;
8371
8372   _startLazyDPSEvaluation ();
8373   while (size--)
8374     {
8375       l = aopGet (left, offset, FALSE, FALSE, NULL);
8376       MOVA (l);
8377       emitcode ("rrc", "a");
8378       if (AOP_SIZE (result) > 1)
8379         aopPut (result, "a", offset--);
8380     }
8381   _endLazyDPSEvaluation ();
8382
8383   /* now we need to put the carry into the
8384      highest order byte of the result */
8385   if (AOP_SIZE (result) > 1)
8386     {
8387       l = aopGet (result, AOP_SIZE (result) - 1, FALSE, FALSE, NULL);
8388       MOVA (l);
8389     }
8390   emitcode ("mov", "acc.7,c");
8391   aopPut (result, "a", AOP_SIZE (result) - 1);
8392   freeAsmop (result, NULL, ic, TRUE);
8393   freeAsmop (left, NULL, ic, TRUE);
8394 }
8395
8396 /*-----------------------------------------------------------------*/
8397 /* genRLC - generate code for rotate left with carry               */
8398 /*-----------------------------------------------------------------*/
8399 static void
8400 genRLC (iCode * ic)
8401 {
8402   operand *left, *result;
8403   int size, offset;
8404   char *l;
8405
8406   D (emitcode (";", "genRLC"));
8407
8408   /* rotate right with carry */
8409   left = IC_LEFT (ic);
8410   result = IC_RESULT (ic);
8411   aopOp (left, ic, FALSE, FALSE);
8412   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8413
8414   /* move it to the result */
8415   size = AOP_SIZE (result);
8416   offset = 0;
8417   if (size--)
8418     {
8419       l = aopGet (left, offset, FALSE, FALSE, NULL);
8420       MOVA (l);
8421       emitcode ("add", "a,acc");
8422       if (AOP_SIZE (result) > 1)
8423         {
8424           aopPut (result, "a", offset++);
8425         }
8426
8427       _startLazyDPSEvaluation ();
8428       while (size--)
8429         {
8430           l = aopGet (left, offset, FALSE, FALSE, NULL);
8431           MOVA (l);
8432           emitcode ("rlc", "a");
8433           if (AOP_SIZE (result) > 1)
8434             aopPut (result, "a", offset++);
8435         }
8436       _endLazyDPSEvaluation ();
8437     }
8438   /* now we need to put the carry into the
8439      highest order byte of the result */
8440   if (AOP_SIZE (result) > 1)
8441     {
8442       l = aopGet (result, 0, FALSE, FALSE, NULL);
8443       MOVA (l);
8444     }
8445   emitcode ("mov", "acc.0,c");
8446   aopPut (result, "a", 0);
8447   freeAsmop (result, NULL, ic, TRUE);
8448   freeAsmop (left, NULL, ic, TRUE);
8449 }
8450
8451 /*-----------------------------------------------------------------*/
8452 /* genGetHbit - generates code get highest order bit               */
8453 /*-----------------------------------------------------------------*/
8454 static void
8455 genGetHbit (iCode * ic)
8456 {
8457   operand *left, *result;
8458
8459   D (emitcode (";", "genGetHbit"));
8460
8461   left = IC_LEFT (ic);
8462   result = IC_RESULT (ic);
8463   aopOp (left, ic, FALSE, FALSE);
8464   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8465
8466   /* get the highest order byte into a */
8467   MOVA (aopGet (left, AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
8468   if (AOP_TYPE (result) == AOP_CRY)
8469     {
8470       emitcode ("rlc", "a");
8471       outBitC (result);
8472     }
8473   else
8474     {
8475       emitcode ("rl", "a");
8476       emitcode ("anl", "a,#1");
8477       outAcc (result);
8478     }
8479
8480
8481   freeAsmop (result, NULL, ic, TRUE);
8482   freeAsmop (left, NULL, ic, TRUE);
8483 }
8484
8485 /*-----------------------------------------------------------------*/
8486 /* genSwap - generates code to swap nibbles or bytes               */
8487 /*-----------------------------------------------------------------*/
8488 static void
8489 genSwap (iCode * ic)
8490 {
8491   operand *left, *result;
8492
8493   D(emitcode (";", "genSwap"));
8494
8495   left = IC_LEFT (ic);
8496   result = IC_RESULT (ic);
8497   aopOp (left, ic, FALSE, FALSE);
8498   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8499
8500   _startLazyDPSEvaluation ();
8501   switch (AOP_SIZE (left))
8502     {
8503     case 1: /* swap nibbles in byte */
8504       MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8505       emitcode ("swap", "a");
8506       aopPut (result, "a", 0);
8507       break;
8508     case 2: /* swap bytes in word */
8509       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
8510         {
8511           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8512           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8513           aopPut (result, "a", 1);
8514         }
8515       else if (operandsEqu (left, result))
8516         {
8517           char * reg = "a";
8518           bool pushedB = FALSE, leftInB = FALSE;
8519
8520           MOVA (aopGet (left, 0, FALSE, FALSE, NULL));
8521           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
8522             {
8523               pushedB = pushB ();
8524               emitcode ("mov", "b,a");
8525               reg = "b";
8526               leftInB = TRUE;
8527             }
8528           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8529           aopPut (result, reg, 1);
8530
8531           if (leftInB)
8532             popB (pushedB);
8533         }
8534       else
8535         {
8536           aopPut (result, aopGet (left, 1, FALSE, FALSE, NULL), 0);
8537           aopPut (result, aopGet (left, 0, FALSE, FALSE, NULL), 1);
8538         }
8539       break;
8540     default:
8541       wassertl(FALSE, "unsupported SWAP operand size");
8542     }
8543   _endLazyDPSEvaluation ();
8544
8545   freeAsmop (result, NULL, ic, TRUE);
8546   freeAsmop (left, NULL, ic, TRUE);
8547 }
8548
8549 /*-----------------------------------------------------------------*/
8550 /* AccRol - rotate left accumulator by known count                 */
8551 /*-----------------------------------------------------------------*/
8552 static void
8553 AccRol (int shCount)
8554 {
8555   shCount &= 0x0007;            // shCount : 0..7
8556
8557   switch (shCount)
8558     {
8559     case 0:
8560       break;
8561     case 1:
8562       emitcode ("rl", "a");
8563       break;
8564     case 2:
8565       emitcode ("rl", "a");
8566       emitcode ("rl", "a");
8567       break;
8568     case 3:
8569       emitcode ("swap", "a");
8570       emitcode ("rr", "a");
8571       break;
8572     case 4:
8573       emitcode ("swap", "a");
8574       break;
8575     case 5:
8576       emitcode ("swap", "a");
8577       emitcode ("rl", "a");
8578       break;
8579     case 6:
8580       emitcode ("rr", "a");
8581       emitcode ("rr", "a");
8582       break;
8583     case 7:
8584       emitcode ("rr", "a");
8585       break;
8586     }
8587 }
8588
8589 /*-----------------------------------------------------------------*/
8590 /* AccLsh - left shift accumulator by known count                  */
8591 /*-----------------------------------------------------------------*/
8592 static void
8593 AccLsh (int shCount)
8594 {
8595   if (shCount != 0)
8596     {
8597       if (shCount == 1)
8598         emitcode ("add", "a,acc");
8599       else if (shCount == 2)
8600         {
8601           emitcode ("add", "a,acc");
8602           emitcode ("add", "a,acc");
8603         }
8604       else
8605         {
8606           /* rotate left accumulator */
8607           AccRol (shCount);
8608           /* and kill the lower order bits */
8609           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
8610         }
8611     }
8612 }
8613
8614 /*-----------------------------------------------------------------*/
8615 /* AccRsh - right shift accumulator by known count                 */
8616 /*-----------------------------------------------------------------*/
8617 static void
8618 AccRsh (int shCount)
8619 {
8620   if (shCount != 0)
8621     {
8622       if (shCount == 1)
8623         {
8624           CLRC;
8625           emitcode ("rrc", "a");
8626         }
8627       else
8628         {
8629           /* rotate right accumulator */
8630           AccRol (8 - shCount);
8631           /* and kill the higher order bits */
8632           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8633         }
8634     }
8635 }
8636
8637 #ifdef BETTER_LITERAL_SHIFT
8638 /*-----------------------------------------------------------------*/
8639 /* AccSRsh - signed right shift accumulator by known count                 */
8640 /*-----------------------------------------------------------------*/
8641 static void
8642 AccSRsh (int shCount)
8643 {
8644   symbol *tlbl;
8645   if (shCount != 0)
8646     {
8647       if (shCount == 1)
8648         {
8649           emitcode ("mov", "c,acc.7");
8650           emitcode ("rrc", "a");
8651         }
8652       else if (shCount == 2)
8653         {
8654           emitcode ("mov", "c,acc.7");
8655           emitcode ("rrc", "a");
8656           emitcode ("mov", "c,acc.7");
8657           emitcode ("rrc", "a");
8658         }
8659       else
8660         {
8661           tlbl = newiTempLabel (NULL);
8662           /* rotate right accumulator */
8663           AccRol (8 - shCount);
8664           /* and kill the higher order bits */
8665           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
8666           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8667           emitcode ("orl", "a,#!constbyte",
8668                     (unsigned char) ~SRMask[shCount]);
8669           emitLabel (tlbl);
8670         }
8671     }
8672 }
8673 #endif
8674
8675 #ifdef BETTER_LITERAL_SHIFT
8676 /*-----------------------------------------------------------------*/
8677 /* shiftR1Left2Result - shift right one byte from left to result   */
8678 /*-----------------------------------------------------------------*/
8679 static void
8680 shiftR1Left2Result (operand * left, int offl,
8681                     operand * result, int offr,
8682                     int shCount, int sign)
8683 {
8684   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
8685   /* shift right accumulator */
8686   if (sign)
8687     AccSRsh (shCount);
8688   else
8689     AccRsh (shCount);
8690   aopPut (result, "a", offr);
8691 }
8692 #endif
8693
8694 #ifdef BETTER_LITERAL_SHIFT
8695 /*-----------------------------------------------------------------*/
8696 /* shiftL1Left2Result - shift left one byte from left to result    */
8697 /*-----------------------------------------------------------------*/
8698 static void
8699 shiftL1Left2Result (operand * left, int offl,
8700                     operand * result, int offr, int shCount)
8701 {
8702   char *l;
8703   l = aopGet (left, offl, FALSE, FALSE, NULL);
8704   MOVA (l);
8705   /* shift left accumulator */
8706   AccLsh (shCount);
8707   aopPut (result, "a", offr);
8708 }
8709 #endif
8710
8711 #ifdef BETTER_LITERAL_SHIFT
8712 /*-----------------------------------------------------------------*/
8713 /* movLeft2Result - move byte from left to result                  */
8714 /*-----------------------------------------------------------------*/
8715 static void
8716 movLeft2Result (operand * left, int offl,
8717                 operand * result, int offr, int sign)
8718 {
8719   char *l;
8720   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8721   {
8722       l = aopGet (left, offl, FALSE, FALSE, NULL);
8723
8724       if (*l == '@' && (IS_AOP_PREG (result)))
8725       {
8726           emitcode ("mov", "a,%s", l);
8727           aopPut (result, "a", offr);
8728       }
8729       else
8730       {
8731           if (!sign)
8732             {
8733               aopPut (result, l, offr);
8734             }
8735           else
8736             {
8737               /* MSB sign in acc.7 ! */
8738               if (getDataSize (left) == offl + 1)
8739                 {
8740                   MOVA (l);
8741                   aopPut (result, "a", offr);
8742                 }
8743             }
8744       }
8745   }
8746 }
8747 #endif
8748
8749 #ifdef BETTER_LITERAL_SHIFT
8750 /*-----------------------------------------------------------------*/
8751 /* AccAXRrl1 - right rotate a:x by 1                               */
8752 /*-----------------------------------------------------------------*/
8753 static void
8754 AccAXRrl1 (char *x)
8755 {
8756   emitcode ("mov", "c,acc.0");
8757   emitcode ("xch", "a,%s", x);
8758   emitcode ("rrc", "a");
8759   emitcode ("xch", "a,%s", x);
8760   emitcode ("rrc", "a");
8761 }
8762 #endif
8763
8764 #ifdef BETTER_LITERAL_SHIFT
8765 //REMOVE ME!!!
8766 /*-----------------------------------------------------------------*/
8767 /* AccAXLrl1 - left rotate a:x by 1                                */
8768 /*-----------------------------------------------------------------*/
8769 static void
8770 AccAXLrl1 (char *x)
8771 {
8772   emitcode ("mov", "c,acc.7");
8773   emitcode ("xch", "a,%s", x);
8774   emitcode ("rlc", "a");
8775   emitcode ("xch", "a,%s", x);
8776   emitcode ("rlc", "a");
8777 }
8778 #endif
8779
8780 #ifdef BETTER_LITERAL_SHIFT
8781 /*-----------------------------------------------------------------*/
8782 /* AccAXRsh1 - right shift c->a:x->c by 1                          */
8783 /*-----------------------------------------------------------------*/
8784 static void
8785 AccAXRsh1 (char *x)
8786 {
8787   emitcode ("rrc", "a");
8788   emitcode ("xch", "a,%s", x);
8789   emitcode ("rrc", "a");
8790   emitcode ("xch", "a,%s", x);
8791 }
8792 #endif
8793
8794 #ifdef BETTER_LITERAL_SHIFT
8795 /*-----------------------------------------------------------------*/
8796 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8797 /*-----------------------------------------------------------------*/
8798 static void
8799 AccAXLsh1 (char *x)
8800 {
8801   emitcode ("xch", "a,%s", x);
8802   emitcode ("add", "a,acc");
8803   emitcode ("xch", "a,%s", x);
8804   emitcode ("rlc", "a");
8805 }
8806 #endif
8807
8808 #ifdef BETTER_LITERAL_SHIFT
8809 /*-----------------------------------------------------------------*/
8810 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8811 /*-----------------------------------------------------------------*/
8812 static void
8813 AccAXLsh (char *x, int shCount)
8814 {
8815   switch (shCount)
8816     {
8817     case 0:
8818       break;
8819     case 1:
8820       AccAXLsh1 (x);
8821       break;
8822     case 2:
8823       AccAXLsh1 (x);
8824       AccAXLsh1 (x);
8825       break;
8826     case 3:
8827     case 4:
8828     case 5:                             // AAAAABBB:CCCCCDDD
8829
8830       AccRol (shCount);                 // BBBAAAAA:CCCCCDDD
8831
8832       emitcode ("anl", "a,#!constbyte",
8833                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8834
8835       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8836
8837       AccRol (shCount);                 // DDDCCCCC:BBB00000
8838
8839       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8840
8841       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8842
8843       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8844
8845       emitcode ("anl", "a,#!constbyte",
8846                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8847
8848       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8849
8850       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8851
8852       break;
8853     case 6:                             // AAAAAABB:CCCCCCDD
8854       emitcode ("anl", "a,#!constbyte",
8855                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8856 #if 1
8857       AccAXRrl1 (x);                    // D000000B:BCCCCCCD
8858       AccAXRrl1 (x);                    // DD000000:BBCCCCCC
8859       emitcode ("xch", "a,%s", x);      // BBCCCCCC:DD000000
8860 #else
8861       emitcode ("mov", "c,acc.0");      // c = B
8862       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8863       emitcode("rrc","a");
8864       emitcode("xch","a,%s", x);
8865       emitcode("rrc","a");
8866       emitcode("mov","c,acc.0"); //<< get correct bit
8867       emitcode("xch","a,%s", x);
8868
8869       emitcode("rrc","a");
8870       emitcode("xch","a,%s", x);
8871       emitcode("rrc","a");
8872       emitcode("xch","a,%s", x);
8873 #endif
8874       break;
8875     case 7:                             // a:x <<= 7
8876
8877       emitcode ("anl", "a,#!constbyte",
8878                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8879
8880       AccAXRrl1 (x);                    // D0000000:BCCCCCCC
8881
8882       emitcode ("xch", "a,%s", x);      // BCCCCCCC:D0000000
8883
8884       break;
8885     default:
8886       break;
8887     }
8888 }
8889 #endif
8890
8891 #ifdef BETTER_LITERAL_SHIFT
8892 //REMOVE ME!!!
8893 /*-----------------------------------------------------------------*/
8894 /* AccAXRsh - right shift a:x known count (0..7)                   */
8895 /*-----------------------------------------------------------------*/
8896 static void
8897 AccAXRsh (char *x, int shCount)
8898 {
8899   switch (shCount)
8900     {
8901     case 0:
8902       break;
8903     case 1:
8904       CLRC;
8905       AccAXRsh1 (x);                    // 0->a:x
8906
8907       break;
8908     case 2:
8909       CLRC;
8910       AccAXRsh1 (x);                    // 0->a:x
8911
8912       CLRC;
8913       AccAXRsh1 (x);                    // 0->a:x
8914
8915       break;
8916     case 3:
8917     case 4:
8918     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8919
8920       AccRol (8 - shCount);             // BBBAAAAA:DDDCCCCC
8921
8922       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8923
8924       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
8925
8926       emitcode ("anl", "a,#!constbyte",
8927                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8928
8929       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8930
8931       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8932
8933       emitcode ("anl", "a,#!constbyte",
8934                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8935
8936       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8937
8938       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8939
8940       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8941
8942       break;
8943     case 6:                             // AABBBBBB:CCDDDDDD
8944
8945       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDE
8946       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
8947
8948       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8949
8950       emitcode ("anl", "a,#!constbyte",
8951                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8952
8953       break;
8954     case 7:                             // ABBBBBBB:CDDDDDDD
8955
8956       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
8957
8958       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8959
8960       emitcode ("anl", "a,#!constbyte",
8961                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8962
8963       break;
8964     default:
8965       break;
8966     }
8967 }
8968 #endif
8969
8970 #ifdef BETTER_LITERAL_SHIFT
8971 /*-----------------------------------------------------------------*/
8972 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8973 /*-----------------------------------------------------------------*/
8974 static void
8975 AccAXRshS (char *x, int shCount)
8976 {
8977   symbol *tlbl;
8978   switch (shCount)
8979     {
8980     case 0:
8981       break;
8982     case 1:
8983       emitcode ("mov", "c,acc.7");
8984       AccAXRsh1 (x);                    // s->a:x
8985
8986       break;
8987     case 2:
8988       emitcode ("mov", "c,acc.7");
8989       AccAXRsh1 (x);                    // s->a:x
8990
8991       emitcode ("mov", "c,acc.7");
8992       AccAXRsh1 (x);                    // s->a:x
8993
8994       break;
8995     case 3:
8996     case 4:
8997     case 5:                             // AAAAABBB:CCCCCDDD = a:x
8998
8999       tlbl = newiTempLabel (NULL);
9000       AccRol (8 - shCount);             // BBBAAAAA:CCCCCDDD
9001
9002       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
9003
9004       AccRol (8 - shCount);             // DDDCCCCC:BBBAAAAA
9005
9006       emitcode ("anl", "a,#!constbyte",
9007                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
9008
9009       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
9010
9011       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
9012
9013       emitcode ("anl", "a,#!constbyte",
9014                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
9015
9016       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
9017
9018       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
9019
9020       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
9021
9022       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9023       emitcode ("orl", "a,#!constbyte",
9024                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
9025
9026       emitLabel (tlbl);
9027       break;                            // SSSSAAAA:BBBCCCCC
9028
9029     case 6:                             // AABBBBBB:CCDDDDDD
9030
9031       tlbl = newiTempLabel (NULL);
9032
9033       AccAXLrl1 (x);                    // ABBBBBBC:CDDDDDDA
9034       AccAXLrl1 (x);                    // BBBBBBCC:DDDDDDAA
9035
9036       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
9037
9038       emitcode ("anl", "a,#!constbyte",
9039                 SRMask[shCount]);       // 000000AA:BBBBBBCC
9040
9041       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9042       emitcode ("orl", "a,#!constbyte",
9043                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
9044
9045       emitLabel (tlbl);
9046       break;
9047     case 7:                             // ABBBBBBB:CDDDDDDD
9048
9049       tlbl = newiTempLabel (NULL);
9050
9051       AccAXLrl1 (x);                    // BBBBBBBC:DDDDDDDA
9052
9053       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
9054
9055       emitcode ("anl", "a,#!constbyte",
9056                 SRMask[shCount]);       // 0000000A:BBBBBBBC
9057
9058       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
9059       emitcode ("orl", "a,#!constbyte",
9060                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
9061
9062       emitLabel (tlbl);
9063       break;
9064     default:
9065       break;
9066     }
9067 }
9068 #endif
9069
9070 #ifdef BETTER_LITERAL_SHIFT
9071 static void
9072 _loadLeftIntoAx(char    **lsb,
9073                 operand *left,
9074                 operand *result,
9075                 int     offl,
9076                 int     offr)
9077 {
9078   // Get the initial value from left into a pair of registers.
9079   // MSB must be in A, LSB can be any register.
9080   //
9081   // If the result is held in registers, it is an optimization
9082   // if the LSB can be held in the register which will hold the,
9083   // result LSB since this saves us from having to copy it into
9084   // the result following AccAXLsh.
9085   //
9086   // If the result is addressed indirectly, this is not a gain.
9087   if (AOP_NEEDSACC(result))
9088   {
9089        char *leftByte;
9090
9091        _startLazyDPSEvaluation();
9092       if (AOP_TYPE(left) == AOP_DPTR2)
9093        {
9094            // Get MSB in A.
9095            MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9096            // get LSB in DP2_RESULT_REG.
9097            leftByte = aopGet (left, offl, FALSE, FALSE, DP2_RESULT_REG);
9098            assert(!strcmp(leftByte, DP2_RESULT_REG));
9099        }
9100        else
9101        {
9102            // get LSB into DP2_RESULT_REG
9103            leftByte = aopGet (left, offl, FALSE, FALSE, NULL);
9104            if (strcmp(leftByte, DP2_RESULT_REG))
9105            {
9106                TR_AP("#7");
9107                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
9108            }
9109            // And MSB in A.
9110            leftByte = aopGet (left, offl + MSB16, FALSE, FALSE, NULL);
9111            assert(strcmp(leftByte, DP2_RESULT_REG));
9112            MOVA (leftByte);
9113        }
9114        _endLazyDPSEvaluation();
9115        *lsb = DP2_RESULT_REG;
9116   }
9117   else
9118   {
9119       if (sameRegs (AOP (result), AOP (left)) &&
9120         ((offl + MSB16) == offr))
9121       {
9122           /* don't crash result[offr] */
9123           MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9124           emitcode ("xch", "a,%s",
9125                     aopGet (left, offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
9126       }
9127       else
9128       {
9129           movLeft2Result (left, offl, result, offr, 0);
9130           MOVA (aopGet (left, offl + MSB16, FALSE, FALSE, NULL));
9131       }
9132       *lsb = aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG);
9133       assert(strcmp(*lsb,"a"));
9134   }
9135 }
9136
9137 static void
9138 _storeAxResults(char    *lsb,
9139                 operand *result,
9140                 int     offr)
9141 {
9142   _startLazyDPSEvaluation();
9143   if (AOP_NEEDSACC(result))
9144   {
9145       /* We have to explicitly update the result LSB.
9146        */
9147       emitcode ("xch","a,%s", lsb);
9148       aopPut (result, "a", offr);
9149       emitcode ("mov","a,%s", lsb);
9150   }
9151   if (getDataSize (result) > 1)
9152   {
9153       aopPut (result, "a", offr + MSB16);
9154   }
9155   _endLazyDPSEvaluation();
9156 }
9157
9158 /*-----------------------------------------------------------------*/
9159 /* shiftL2Left2Result - shift left two bytes from left to result   */
9160 /*-----------------------------------------------------------------*/
9161 static void
9162 shiftL2Left2Result (operand * left, int offl,
9163                     operand * result, int offr, int shCount)
9164 {
9165   char *lsb;
9166
9167   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9168
9169   AccAXLsh (lsb, shCount);
9170
9171   _storeAxResults(lsb, result, offr);
9172 }
9173 #endif
9174
9175 #ifdef BETTER_LITERAL_SHIFT
9176 /*-----------------------------------------------------------------*/
9177 /* shiftR2Left2Result - shift right two bytes from left to result  */
9178 /*-----------------------------------------------------------------*/
9179 static void
9180 shiftR2Left2Result (operand * left, int offl,
9181                     operand * result, int offr,
9182                     int shCount, int sign)
9183 {
9184   char *lsb;
9185
9186   _loadLeftIntoAx(&lsb, left, result, offl, offr);
9187
9188   /* a:x >> shCount (x = lsb(result)) */
9189   if (sign)
9190   {
9191      AccAXRshS(lsb, shCount);
9192   }
9193   else
9194   {
9195     AccAXRsh(lsb, shCount);
9196   }
9197
9198   _storeAxResults(lsb, result, offr);
9199 }
9200 #endif
9201
9202 /*-----------------------------------------------------------------*/
9203 /* shiftLLeftOrResult - shift left one byte from left, or to result */
9204 /*-----------------------------------------------------------------*/
9205 static void
9206 shiftLLeftOrResult (operand * left, int offl,
9207                     operand * result, int offr, int shCount)
9208 {
9209   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9210   /* shift left accumulator */
9211   AccLsh (shCount);
9212   /* or with result */
9213   emitcode ("orl", "a,%s",
9214             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9215   /* back to result */
9216   aopPut (result, "a", offr);
9217 }
9218
9219 #if 0
9220 //REMOVE ME!!!
9221 /*-----------------------------------------------------------------*/
9222 /* shiftRLeftOrResult - shift right one byte from left,or to result */
9223 /*-----------------------------------------------------------------*/
9224 static void
9225 shiftRLeftOrResult (operand * left, int offl,
9226                     operand * result, int offr, int shCount)
9227 {
9228   MOVA (aopGet (left, offl, FALSE, FALSE, NULL));
9229   /* shift right accumulator */
9230   AccRsh (shCount);
9231   /* or with result */
9232   emitcode ("orl", "a,%s",
9233             aopGet (result, offr, FALSE, FALSE, DP2_RESULT_REG));
9234   /* back to result */
9235   aopPut (result, "a", offr);
9236 }
9237 #endif
9238
9239 #ifdef BETTER_LITERAL_SHIFT
9240 /*-----------------------------------------------------------------*/
9241 /* genlshOne - left shift a one byte quantity by known count       */
9242 /*-----------------------------------------------------------------*/
9243 static void
9244 genlshOne (operand * result, operand * left, int shCount)
9245 {
9246   D (emitcode (";", "genlshOne"));
9247
9248   shiftL1Left2Result (left, LSB, result, LSB, shCount);
9249 }
9250 #endif
9251
9252 #ifdef BETTER_LITERAL_SHIFT
9253 /*-----------------------------------------------------------------*/
9254 /* genlshTwo - left shift two bytes by known amount != 0           */
9255 /*-----------------------------------------------------------------*/
9256 static void
9257 genlshTwo (operand * result, operand * left, int shCount)
9258 {
9259   int size;
9260
9261   D (emitcode (";", "genlshTwo"));
9262
9263   size = getDataSize (result);
9264
9265   /* if shCount >= 8 */
9266   if (shCount >= 8)
9267   {
9268       shCount -= 8;
9269
9270       _startLazyDPSEvaluation();
9271
9272       if (size > 1)
9273         {
9274           if (shCount)
9275           {
9276             _endLazyDPSEvaluation();
9277             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9278             aopPut (result, zero, LSB);
9279           }
9280           else
9281           {
9282             movLeft2Result (left, LSB, result, MSB16, 0);
9283             aopPut (result, zero, LSB);
9284             _endLazyDPSEvaluation();
9285           }
9286         }
9287         else
9288         {
9289           aopPut (result, zero, LSB);
9290           _endLazyDPSEvaluation();
9291         }
9292   }
9293
9294   /*  1 <= shCount <= 7 */
9295   else
9296     {
9297       if (size == 1)
9298         shiftL1Left2Result (left, LSB, result, LSB, shCount);
9299       else
9300         shiftL2Left2Result (left, LSB, result, LSB, shCount);
9301     }
9302 }
9303 #endif
9304
9305 #if 0
9306 //REMOVE ME!!!
9307 /*-----------------------------------------------------------------*/
9308 /* shiftLLong - shift left one long from left to result            */
9309 /* offl = LSB or MSB16                                             */
9310 /*-----------------------------------------------------------------*/
9311 static void
9312 shiftLLong (operand * left, operand * result, int offr)
9313 {
9314   char *l;
9315   int size = AOP_SIZE (result);
9316
9317   if (size >= LSB + offr)
9318     {
9319       l = aopGet (left, LSB, FALSE, FALSE, NULL);
9320       MOVA (l);
9321       emitcode ("add", "a,acc");
9322       if (sameRegs (AOP (left), AOP (result)) &&
9323           size >= MSB16 + offr && offr != LSB)
9324         emitcode ("xch", "a,%s",
9325                   aopGet (left, LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
9326       else
9327         aopPut (result, "a", LSB + offr);
9328     }
9329
9330   if (size >= MSB16 + offr)
9331     {
9332       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
9333         {
9334           l = aopGet (left, MSB16, FALSE, FALSE, TRUE);
9335           MOVA (l);
9336         }
9337       emitcode ("rlc", "a");
9338       if (sameRegs (AOP (left), AOP (result)) &&
9339           size >= MSB24 + offr && offr != LSB)
9340         emitcode ("xch", "a,%s",
9341                   aopGet (left, MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
9342       else
9343         aopPut (result, "a", MSB16 + offr);
9344     }
9345
9346   if (size >= MSB24 + offr)
9347     {
9348       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB24 + offr && offr != LSB))
9349         {
9350           l = aopGet (left, MSB24, FALSE, FALSE, NULL);
9351           MOVA (l);
9352         }
9353       emitcode ("rlc", "a");
9354       if (sameRegs (AOP (left), AOP (result)) &&
9355           size >= MSB32 + offr && offr != LSB)
9356         emitcode ("xch", "a,%s",
9357                   aopGet (left, MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
9358       else
9359         aopPut (result, "a", MSB24 + offr);
9360     }
9361
9362   if (size > MSB32 + offr)
9363     {
9364       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
9365         {
9366           l = aopGet (left, MSB32, FALSE, FALSE, NULL);
9367           MOVA (l);
9368         }
9369       emitcode ("rlc", "a");
9370       aopPut (result, "a", MSB32 + offr);
9371     }
9372   if (offr != LSB)
9373     aopPut (result, zero, LSB);
9374 }
9375 #endif
9376
9377 #if 0
9378 //REMOVE ME!!!
9379 /*-----------------------------------------------------------------*/
9380 /* genlshFour - shift four byte by a known amount != 0             */
9381 /*-----------------------------------------------------------------*/
9382 static void
9383 genlshFour (operand * result, operand * left, int shCount)
9384 {
9385   int size;
9386
9387   D (emitcode (";", "genlshFour"));
9388
9389   size = AOP_SIZE (result);
9390
9391   /* if shifting more that 3 bytes */
9392   if (shCount >= 24)
9393     {
9394       shCount -= 24;
9395       if (shCount)
9396         /* lowest order of left goes to the highest
9397            order of the destination */
9398         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
9399       else
9400         movLeft2Result (left, LSB, result, MSB32, 0);
9401       aopPut (result, zero, LSB);
9402       aopPut (result, zero, MSB16);
9403       aopPut (result, zero, MSB24);
9404       return;
9405     }
9406
9407   /* more than two bytes */
9408   else if (shCount >= 16)
9409     {
9410       /* lower order two bytes goes to higher order two bytes */
9411       shCount -= 16;
9412       /* if some more remaining */
9413       if (shCount)
9414         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
9415       else
9416         {
9417           movLeft2Result (left, MSB16, result, MSB32, 0);
9418           movLeft2Result (left, LSB, result, MSB24, 0);
9419         }
9420       aopPut (result, zero, MSB16);
9421       aopPut (result, zero, LSB);
9422       return;
9423     }
9424
9425   /* if more than 1 byte */
9426   else if (shCount >= 8)
9427     {
9428       /* lower order three bytes goes to higher order  three bytes */
9429       shCount -= 8;
9430       if (size == 2)
9431         {
9432           if (shCount)
9433             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9434           else
9435             movLeft2Result (left, LSB, result, MSB16, 0);
9436         }
9437       else
9438         {                       /* size = 4 */
9439           if (shCount == 0)
9440             {
9441               movLeft2Result (left, MSB24, result, MSB32, 0);
9442               movLeft2Result (left, MSB16, result, MSB24, 0);
9443               movLeft2Result (left, LSB, result, MSB16, 0);
9444               aopPut (result, zero, LSB);
9445             }
9446           else if (shCount == 1)
9447             shiftLLong (left, result, MSB16);
9448           else
9449             {
9450               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
9451               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
9452               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
9453               aopPut (result, zero, LSB);
9454             }
9455         }
9456     }
9457
9458   /* 1 <= shCount <= 7 */
9459   else if (shCount <= 2)
9460     {
9461       shiftLLong (left, result, LSB);
9462       if (shCount == 2)
9463         shiftLLong (result, result, LSB);
9464     }
9465   /* 3 <= shCount <= 7, optimize */
9466   else
9467     {
9468       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
9469       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
9470       shiftL2Left2Result (left, LSB, result, LSB, shCount);
9471     }
9472 }
9473 #endif
9474
9475 #ifdef BETTER_LITERAL_SHIFT
9476 /*-----------------------------------------------------------------*/
9477 /* genLeftShiftLiteral - left shifting by known count              */
9478 /*-----------------------------------------------------------------*/
9479 static bool
9480 genLeftShiftLiteral (operand * left,
9481                      operand * right,
9482                      operand * result,
9483                      iCode * ic)
9484 {
9485   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9486   int size;
9487
9488   size = getSize (operandType (result));
9489
9490   D (emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
9491
9492   /* We only handle certain easy cases so far. */
9493   if ((shCount != 0)
9494    && (shCount < (size * 8))
9495    && (size != 1)
9496    && (size != 2))
9497   {
9498       D(emitcode (";", "genLeftShiftLiteral wimping out"););
9499       return FALSE;
9500   }
9501
9502   freeAsmop (right, NULL, ic, TRUE);
9503
9504   aopOp(left, ic, FALSE, FALSE);
9505   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
9506
9507 #if 0 // debug spew
9508   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
9509   {
9510         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
9511         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
9512         {
9513            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
9514         }
9515   }
9516   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
9517   {
9518         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
9519         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
9520         {
9521            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
9522         }
9523   }
9524 #endif
9525
9526 #if VIEW_SIZE
9527   emitcode ("; shift left ", "result %d, left %d", size,
9528             AOP_SIZE (left));
9529 #endif
9530
9531   /* I suppose that the left size >= result size */
9532   if (shCount == 0)
9533   {
9534         _startLazyDPSEvaluation();
9535         while (size--)
9536         {
9537           movLeft2Result (left, size, result, size, 0);
9538         }
9539         _endLazyDPSEvaluation();
9540   }
9541   else if (shCount >= (size * 8))
9542   {
9543     _startLazyDPSEvaluation();
9544     while (size--)
9545     {
9546       aopPut (result, zero, size);
9547     }
9548     _endLazyDPSEvaluation();
9549   }
9550   else
9551   {
9552       switch (size)
9553         {
9554         case 1:
9555           genlshOne (result, left, shCount);
9556           break;
9557
9558         case 2:
9559           genlshTwo (result, left, shCount);
9560           break;
9561 #if 0
9562         case 4:
9563           genlshFour (result, left, shCount);
9564           break;
9565 #endif
9566         default:
9567           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
9568                   "*** ack! mystery literal shift!\n");
9569           break;
9570         }
9571     }
9572   freeAsmop (result, NULL, ic, TRUE);
9573   freeAsmop (left, NULL, ic, TRUE);
9574   return TRUE;
9575 }
9576 #endif
9577
9578 /*-----------------------------------------------------------------*/
9579 /* genLeftShift - generates code for left shifting                 */
9580 /*-----------------------------------------------------------------*/
9581 static void
9582 genLeftShift (iCode * ic)
9583 {
9584   operand *left, *right, *result;
9585   int size, offset;
9586   char *l;
9587   symbol *tlbl, *tlbl1;
9588   bool pushedB;
9589
9590   D (emitcode (";", "genLeftShift"));
9591
9592   right = IC_RIGHT (ic);
9593   left = IC_LEFT (ic);
9594   result = IC_RESULT (ic);
9595
9596   aopOp (right, ic, FALSE, FALSE);
9597
9598
9599 #ifdef BETTER_LITERAL_SHIFT
9600   /* if the shift count is known then do it
9601      as efficiently as possible */
9602   if (AOP_TYPE (right) == AOP_LIT)
9603     {
9604       if (genLeftShiftLiteral (left, right, result, ic))
9605       {
9606         return;
9607       }
9608     }
9609 #endif
9610
9611   /* shift count is unknown then we have to form
9612      a loop get the loop count in B : Note: we take
9613      only the lower order byte since shifting
9614      more that 32 bits make no sense anyway, ( the
9615      largest size of an object can be only 32 bits ) */
9616
9617   pushedB = pushB ();
9618   if (AOP_TYPE (right) == AOP_LIT)
9619   {
9620       /* Really should be handled by genLeftShiftLiteral,
9621        * but since I'm too lazy to fix that today, at least we can make
9622        * some small improvement.
9623        */
9624        emitcode("mov", "b,#!constbyte",
9625                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
9626   }
9627   else
9628   {
9629       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
9630       emitcode ("inc", "b");
9631   }
9632   freeAsmop (right, NULL, ic, TRUE);
9633   aopOp (left, ic, FALSE, FALSE);
9634   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9635
9636   /* now move the left to the result if they are not the same */
9637   if (!sameRegs (AOP (left), AOP (result)) &&
9638       AOP_SIZE (result) > 1)
9639     {
9640
9641       size = AOP_SIZE (result);
9642       offset = 0;
9643       _startLazyDPSEvaluation ();
9644       while (size--)
9645         {
9646           l = aopGet (left, offset, FALSE, TRUE, NULL);
9647           if (*l == '@' && (IS_AOP_PREG (result)))
9648             {
9649
9650               emitcode ("mov", "a,%s", l);
9651               aopPut (result, "a", offset);
9652             }
9653           else
9654             aopPut (result, l, offset);
9655           offset++;
9656         }
9657       _endLazyDPSEvaluation ();
9658     }
9659
9660   tlbl = newiTempLabel (NULL);
9661   size = AOP_SIZE (result);
9662   offset = 0;
9663   tlbl1 = newiTempLabel (NULL);
9664
9665   /* if it is only one byte then */
9666   if (size == 1)
9667     {
9668       symbol *tlbl1 = newiTempLabel (NULL);
9669
9670       l = aopGet (left, 0, FALSE, FALSE, NULL);
9671       MOVA (l);
9672       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9673       emitLabel (tlbl);
9674       emitcode ("add", "a,acc");
9675       emitLabel (tlbl1);
9676       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9677       popB (pushedB);
9678       aopPut (result, "a", 0);
9679       goto release;
9680     }
9681
9682   reAdjustPreg (AOP (result));
9683
9684   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9685   emitLabel (tlbl);
9686   l = aopGet (result, offset, FALSE, FALSE, NULL);
9687   MOVA (l);
9688   emitcode ("add", "a,acc");
9689   aopPut (result, "a", offset++);
9690   _startLazyDPSEvaluation ();
9691   while (--size)
9692     {
9693       l = aopGet (result, offset, FALSE, FALSE, NULL);
9694       MOVA (l);
9695       emitcode ("rlc", "a");
9696       aopPut (result, "a", offset++);
9697     }
9698   _endLazyDPSEvaluation ();
9699   reAdjustPreg (AOP (result));
9700
9701   emitLabel (tlbl1);
9702   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9703   popB (pushedB);
9704 release:
9705   freeAsmop (result, NULL, ic, TRUE);
9706   freeAsmop (left, NULL, ic, TRUE);
9707 }
9708
9709 #ifdef BETTER_LITERAL_SHIFT
9710 /*-----------------------------------------------------------------*/
9711 /* genrshOne - right shift a one byte quantity by known count      */
9712 /*-----------------------------------------------------------------*/
9713 static void
9714 genrshOne (operand * result, operand * left,
9715            int shCount, int sign)
9716 {
9717   D (emitcode (";", "genrshOne"));
9718
9719   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9720 }
9721 #endif
9722
9723 #ifdef BETTER_LITERAL_SHIFT
9724 /*-----------------------------------------------------------------*/
9725 /* genrshTwo - right shift two bytes by known amount != 0          */
9726 /*-----------------------------------------------------------------*/
9727 static void
9728 genrshTwo (operand * result, operand * left,
9729            int shCount, int sign)
9730 {
9731   D (emitcode (";", "genrshTwo"));
9732
9733   /* if shCount >= 8 */
9734   if (shCount >= 8)
9735     {
9736       shCount -= 8;
9737       _startLazyDPSEvaluation();
9738       if (shCount)
9739         shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9740       else
9741         movLeft2Result (left, MSB16, result, LSB, sign);
9742       addSign (result, MSB16, sign);
9743       _endLazyDPSEvaluation();
9744     }
9745
9746   /*  1 <= shCount <= 7 */
9747   else
9748     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9749 }
9750 #endif
9751
9752 /*-----------------------------------------------------------------*/
9753 /* shiftRLong - shift right one long from left to result           */
9754 /* offl = LSB or MSB16                                             */
9755 /*-----------------------------------------------------------------*/
9756 static void
9757 shiftRLong (operand * left, int offl,
9758             operand * result, int sign)
9759 {
9760   bool overlapping = regsInCommon (left, result) || operandsEqu(left, result);
9761
9762   if (overlapping && offl>1)
9763     {
9764       // we are in big trouble, but this shouldn't happen
9765       werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9766     }
9767
9768   MOVA (aopGet (left, MSB32, FALSE, FALSE, NULL));
9769
9770   if (offl==MSB16)
9771     {
9772       // shift is > 8
9773       if (sign)
9774         {
9775           emitcode ("rlc", "a");
9776           emitcode ("subb", "a,acc");
9777           emitcode ("xch", "a,%s",
9778                     aopGet(left, MSB32, FALSE, FALSE, DP2_RESULT_REG));
9779         }
9780       else
9781         {
9782           aopPut (result, zero, MSB32);
9783         }
9784     }
9785
9786   if (!sign)
9787     {
9788       emitcode ("clr", "c");
9789     }
9790   else
9791     {
9792       emitcode ("mov", "c,acc.7");
9793     }
9794
9795   emitcode ("rrc", "a");
9796
9797   if (overlapping && offl==MSB16)
9798     {
9799       emitcode ("xch", "a,%s", aopGet (left, MSB24, FALSE, FALSE, DP2_RESULT_REG));
9800     }
9801   else
9802     {
9803       aopPut (result, "a", MSB32 - offl);
9804       MOVA (aopGet (left, MSB24, FALSE, FALSE, NULL));
9805     }
9806
9807   emitcode ("rrc", "a");
9808
9809   if (overlapping && offl==MSB16)
9810     {
9811       emitcode ("xch", "a,%s", aopGet (left, MSB16, FALSE, FALSE, DP2_RESULT_REG));
9812     }
9813   else
9814     {
9815       aopPut (result, "a", MSB24 - offl);
9816       MOVA (aopGet (left, MSB16, FALSE, FALSE, NULL));
9817     }
9818
9819   emitcode ("rrc", "a");
9820   if (offl != LSB)
9821     {
9822       aopPut (result, "a", MSB16 - offl);
9823     }
9824   else
9825     {
9826       if (overlapping && offl==MSB16)
9827         {
9828           emitcode ("xch", "a,%s", aopGet (left, LSB, FALSE, FALSE, DP2_RESULT_REG));
9829         }
9830       else
9831         {
9832           aopPut (result, "a", MSB16 - offl);
9833           MOVA (aopGet (left, LSB, FALSE, FALSE, NULL));
9834         }
9835       emitcode ("rrc", "a");
9836       aopPut (result, "a", LSB);
9837     }
9838 }
9839
9840 /*-----------------------------------------------------------------*/
9841 /* genrshFour - shift four byte by a known amount != 0             */
9842 /*-----------------------------------------------------------------*/
9843 static void
9844 genrshFour (operand * result, operand * left,
9845             int shCount, int sign)
9846 {
9847   D (emitcode (";", "genrshFour"));
9848
9849   /* if shifting more that 3 bytes */
9850   if (shCount >= 24)
9851     {
9852       shCount -= 24;
9853       _startLazyDPSEvaluation();
9854       if (shCount)
9855         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9856       else
9857         movLeft2Result (left, MSB32, result, LSB, sign);
9858       addSign (result, MSB16, sign);
9859       _endLazyDPSEvaluation();
9860     }
9861   else if (shCount >= 16)
9862     {
9863       shCount -= 16;
9864       _startLazyDPSEvaluation();
9865       if (shCount)
9866         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9867       else
9868         {
9869           movLeft2Result (left, MSB24, result, LSB, 0);
9870           movLeft2Result (left, MSB32, result, MSB16, sign);
9871         }
9872       addSign (result, MSB24, sign);
9873       _endLazyDPSEvaluation();
9874     }
9875   else if (shCount >= 8)
9876     {
9877       shCount -= 8;
9878       _startLazyDPSEvaluation();
9879       if (shCount == 1)
9880         {
9881           shiftRLong (left, MSB16, result, sign);
9882         }
9883       else if (shCount == 0)
9884         {
9885           movLeft2Result (left, MSB16, result, LSB, 0);
9886           movLeft2Result (left, MSB24, result, MSB16, 0);
9887           movLeft2Result (left, MSB32, result, MSB24, sign);
9888           addSign (result, MSB32, sign);
9889         }
9890       else
9891         {
9892           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9893           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9894           /* the last shift is signed */
9895           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9896           addSign (result, MSB32, sign);
9897         }
9898         _endLazyDPSEvaluation();
9899     }
9900   else
9901     {
9902       /* 1 <= shCount <= 7 */
9903       if (shCount <= 2)
9904         {
9905           shiftRLong (left, LSB, result, sign);
9906           if (shCount == 2)
9907             shiftRLong (result, LSB, result, sign);
9908         }
9909       else
9910         {
9911           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9912           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9913           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9914         }
9915     }
9916 }
9917
9918 #ifdef BETTER_LITERAL_SHIFT
9919 /*-----------------------------------------------------------------*/
9920 /* genRightShiftLiteral - right shifting by known count            */
9921 /*-----------------------------------------------------------------*/
9922 static bool
9923 genRightShiftLiteral (operand * left,
9924                       operand * right,
9925                       operand * result,
9926                       iCode * ic,
9927                       int sign)
9928 {
9929   int shCount = (int) ulFromVal (AOP (right)->aopu.aop_lit);
9930   int size;
9931
9932   size = getSize (operandType (result));
9933
9934   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9935
9936   /* We only handle certain easy cases so far. */
9937   if ((shCount != 0)
9938    && (shCount < (size * 8))
9939    && (size != 1)
9940    && (size != 2)
9941    && (size != 4))
9942   {
9943       D(emitcode (";", "genRightShiftLiteral wimping out"););
9944       return FALSE;
9945   }
9946
9947   freeAsmop (right, NULL, ic, TRUE);
9948
9949   aopOp (left, ic, FALSE, FALSE);
9950   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9951
9952 #if VIEW_SIZE
9953   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9954             AOP_SIZE (left));
9955 #endif
9956
9957   /* test the LEFT size !!! */
9958
9959   /* I suppose that the left size >= result size */
9960   if (shCount == 0)
9961   {
9962       size = getDataSize (result);
9963       _startLazyDPSEvaluation();
9964       while (size--)
9965         movLeft2Result (left, size, result, size, 0);
9966       _endLazyDPSEvaluation();
9967   }
9968   else if (shCount >= (size * 8))
9969     {
9970       if (sign)
9971         {
9972           /* get sign in acc.7 */
9973           MOVA (aopGet (left, size - 1, FALSE, FALSE, NULL));
9974         }
9975       addSign (result, LSB, sign);
9976     }
9977   else
9978     {
9979       switch (size)
9980         {
9981         case 1:
9982           genrshOne (result, left, shCount, sign);
9983           break;
9984
9985         case 2:
9986           genrshTwo (result, left, shCount, sign);
9987           break;
9988 #if 1
9989         case 4:
9990           genrshFour (result, left, shCount, sign);
9991           break;
9992 #endif
9993         default:
9994           break;
9995         }
9996     }
9997   freeAsmop (result, NULL, ic, TRUE);
9998   freeAsmop (left, NULL, ic, TRUE);
9999
10000   return TRUE;
10001 }
10002 #endif
10003
10004 /*-----------------------------------------------------------------*/
10005 /* genSignedRightShift - right shift of signed number              */
10006 /*-----------------------------------------------------------------*/
10007 static void
10008 genSignedRightShift (iCode * ic)
10009 {
10010   operand *right, *left, *result;
10011   int size, offset;
10012   char *l;
10013   symbol *tlbl, *tlbl1;
10014   bool pushedB;
10015
10016   D (emitcode (";", "genSignedRightShift"));
10017
10018   /* we do it the hard way put the shift count in b
10019      and loop thru preserving the sign */
10020
10021   right = IC_RIGHT (ic);
10022   left = IC_LEFT (ic);
10023   result = IC_RESULT (ic);
10024
10025   aopOp (right, ic, FALSE, FALSE);
10026
10027 #ifdef BETTER_LITERAL_SHIFT
10028   if (AOP_TYPE (right) == AOP_LIT)
10029     {
10030       if (genRightShiftLiteral (left, right, result, ic, 1))
10031       {
10032         return;
10033       }
10034     }
10035 #endif
10036   /* shift count is unknown then we have to form
10037      a loop get the loop count in B : Note: we take
10038      only the lower order byte since shifting
10039      more that 32 bits make no sense anyway, ( the
10040      largest size of an object can be only 32 bits ) */
10041
10042   pushedB = pushB ();
10043   if (AOP_TYPE (right) == AOP_LIT)
10044   {
10045       /* Really should be handled by genRightShiftLiteral,
10046        * but since I'm too lazy to fix that today, at least we can make
10047        * some small improvement.
10048        */
10049        emitcode("mov", "b,#!constbyte",
10050                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10051   }
10052   else
10053   {
10054         MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10055         emitcode ("inc", "b");
10056   }
10057   freeAsmop (right, NULL, ic, TRUE);
10058   aopOp (left, ic, FALSE, FALSE);
10059   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10060
10061   /* now move the left to the result if they are not the
10062      same */
10063   if (!sameRegs (AOP (left), AOP (result)) &&
10064       AOP_SIZE (result) > 1)
10065     {
10066
10067       size = AOP_SIZE (result);
10068       offset = 0;
10069       _startLazyDPSEvaluation ();
10070       while (size--)
10071         {
10072           l = aopGet (left, offset, FALSE, TRUE, NULL);
10073           if (*l == '@' && IS_AOP_PREG (result))
10074             {
10075
10076               emitcode ("mov", "a,%s", l);
10077               aopPut (result, "a", offset);
10078             }
10079           else
10080             aopPut (result, l, offset);
10081           offset++;
10082         }
10083       _endLazyDPSEvaluation ();
10084     }
10085
10086   /* mov the highest order bit to OVR */
10087   tlbl = newiTempLabel (NULL);
10088   tlbl1 = newiTempLabel (NULL);
10089
10090   size = AOP_SIZE (result);
10091   offset = size - 1;
10092   MOVA (aopGet (left, offset, FALSE, FALSE, NULL));
10093   emitcode ("rlc", "a");
10094   emitcode ("mov", "ov,c");
10095   /* if it is only one byte then */
10096   if (size == 1)
10097     {
10098       l = aopGet (left, 0, FALSE, FALSE, NULL);
10099       MOVA (l);
10100       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10101       emitLabel (tlbl);
10102       emitcode ("mov", "c,ov");
10103       emitcode ("rrc", "a");
10104       emitLabel (tlbl1);
10105       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10106       popB (pushedB);
10107       aopPut (result, "a", 0);
10108       goto release;
10109     }
10110
10111   reAdjustPreg (AOP (result));
10112   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10113   emitLabel (tlbl);
10114   emitcode ("mov", "c,ov");
10115   _startLazyDPSEvaluation ();
10116   while (size--)
10117     {
10118       l = aopGet (result, offset, FALSE, FALSE, NULL);
10119       MOVA (l);
10120       emitcode ("rrc", "a");
10121       aopPut (result, "a", offset--);
10122     }
10123   _endLazyDPSEvaluation ();
10124   reAdjustPreg (AOP (result));
10125   emitLabel (tlbl1);
10126   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10127   popB (pushedB);
10128
10129 release:
10130   freeAsmop (result, NULL, ic, TRUE);
10131   freeAsmop (left, NULL, ic, TRUE);
10132 }
10133
10134 /*-----------------------------------------------------------------*/
10135 /* genRightShift - generate code for right shifting                */
10136 /*-----------------------------------------------------------------*/
10137 static void
10138 genRightShift (iCode * ic)
10139 {
10140   operand *right, *left, *result;
10141   sym_link *letype;
10142   int size, offset;
10143   char *l;
10144   symbol *tlbl, *tlbl1;
10145   bool pushedB;
10146
10147   D (emitcode (";", "genRightShift"));
10148
10149   /* if signed then we do it the hard way preserve the
10150      sign bit moving it inwards */
10151   letype = getSpec (operandType (IC_LEFT (ic)));
10152
10153   if (!SPEC_USIGN (letype))
10154     {
10155       genSignedRightShift (ic);
10156       return;
10157     }
10158
10159   /* signed & unsigned types are treated the same : i.e. the
10160      signed is NOT propagated inwards : quoting from the
10161      ANSI - standard : "for E1 >> E2, is equivalent to division
10162      by 2**E2 if unsigned or if it has a non-negative value,
10163      otherwise the result is implementation defined ", MY definition
10164      is that the sign does not get propagated */
10165
10166   right = IC_RIGHT (ic);
10167   left = IC_LEFT (ic);
10168   result = IC_RESULT (ic);
10169
10170   aopOp (right, ic, FALSE, FALSE);
10171
10172 #ifdef BETTER_LITERAL_SHIFT
10173   /* if the shift count is known then do it
10174      as efficiently as possible */
10175   if (AOP_TYPE (right) == AOP_LIT)
10176     {
10177       if (genRightShiftLiteral (left, right, result, ic, 0))
10178       {
10179         return;
10180       }
10181     }
10182 #endif
10183
10184   /* shift count is unknown then we have to form
10185      a loop get the loop count in B : Note: we take
10186      only the lower order byte since shifting
10187      more that 32 bits make no sense anyway, ( the
10188      largest size of an object can be only 32 bits ) */
10189
10190   pushedB = pushB ();
10191   if (AOP_TYPE (right) == AOP_LIT)
10192   {
10193       /* Really should be handled by genRightShiftLiteral,
10194        * but since I'm too lazy to fix that today, at least we can make
10195        * some small improvement.
10196        */
10197        emitcode("mov", "b,#!constbyte",
10198                 ((int) ulFromVal (AOP (right)->aopu.aop_lit)) + 1);
10199   }
10200   else
10201   {
10202       MOVB (aopGet (right, 0, FALSE, FALSE, "b"));
10203       emitcode ("inc", "b");
10204   }
10205   freeAsmop (right, NULL, ic, TRUE);
10206   aopOp (left, ic, FALSE, FALSE);
10207   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
10208
10209   /* now move the left to the result if they are not the
10210      same */
10211   if (!sameRegs (AOP (left), AOP (result)) &&
10212       AOP_SIZE (result) > 1)
10213     {
10214       size = AOP_SIZE (result);
10215       offset = 0;
10216       _startLazyDPSEvaluation ();
10217       while (size--)
10218         {
10219           l = aopGet (left, offset, FALSE, TRUE, NULL);
10220           if (*l == '@' && IS_AOP_PREG (result))
10221             {
10222
10223               emitcode ("mov", "a,%s", l);
10224               aopPut (result, "a", offset);
10225             }
10226           else
10227             aopPut (result, l, offset);
10228           offset++;
10229         }
10230       _endLazyDPSEvaluation ();
10231     }
10232
10233   tlbl = newiTempLabel (NULL);
10234   tlbl1 = newiTempLabel (NULL);
10235   size = AOP_SIZE (result);
10236   offset = size - 1;
10237
10238   /* if it is only one byte then */
10239   if (size == 1)
10240     {
10241       l = aopGet (left, 0, FALSE, FALSE, NULL);
10242       MOVA (l);
10243       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10244       emitLabel (tlbl);
10245       CLRC;
10246       emitcode ("rrc", "a");
10247       emitLabel (tlbl1);
10248       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10249       popB (pushedB);
10250       aopPut (result, "a", 0);
10251       goto release;
10252     }
10253
10254   reAdjustPreg (AOP (result));
10255   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
10256   emitLabel (tlbl);
10257   CLRC;
10258   _startLazyDPSEvaluation ();
10259   while (size--)
10260     {
10261       l = aopGet (result, offset, FALSE, FALSE, NULL);
10262       MOVA (l);
10263       emitcode ("rrc", "a");
10264       aopPut (result, "a", offset--);
10265     }
10266   _endLazyDPSEvaluation ();
10267   reAdjustPreg (AOP (result));
10268
10269   emitLabel (tlbl1);
10270   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
10271   popB (pushedB);
10272
10273 release:
10274   freeAsmop (result, NULL, ic, TRUE);
10275   freeAsmop (left, NULL, ic, TRUE);
10276 }
10277
10278 /*-----------------------------------------------------------------*/
10279 /* emitPtrByteGet - emits code to get a byte into A through a      */
10280 /*                  pointer register (R0, R1, or DPTR). The        */
10281 /*                  original value of A can be preserved in B.     */
10282 /*-----------------------------------------------------------------*/
10283 static void
10284 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
10285 {
10286   switch (p_type)
10287     {
10288     case IPOINTER:
10289     case POINTER:
10290       if (preserveAinB)
10291         emitcode ("mov", "b,a");
10292       emitcode ("mov", "a,@%s", rname);
10293       break;
10294
10295     case PPOINTER:
10296       if (preserveAinB)
10297         emitcode ("mov", "b,a");
10298       emitcode ("movx", "a,@%s", rname);
10299       break;
10300
10301     case FPOINTER:
10302       if (preserveAinB)
10303         emitcode ("mov", "b,a");
10304       emitcode ("movx", "a,@dptr");
10305       break;
10306
10307     case CPOINTER:
10308       if (preserveAinB)
10309         emitcode ("mov", "b,a");
10310       emitcode ("clr", "a");
10311       emitcode ("movc", "a,@a+dptr");
10312       break;
10313
10314     case GPOINTER:
10315       if (preserveAinB)
10316         {
10317           emitcode ("push", "b");
10318           emitcode ("push", "acc");
10319         }
10320       emitcode ("lcall", "__gptrget");
10321       if (preserveAinB)
10322         emitcode ("pop", "b");
10323       break;
10324     }
10325 }
10326
10327 /*-----------------------------------------------------------------*/
10328 /* emitPtrByteSet - emits code to set a byte from src through a    */
10329 /*                  pointer register (R0, R1, or DPTR).            */
10330 /*-----------------------------------------------------------------*/
10331 static void
10332 emitPtrByteSet (char *rname, int p_type, char *src)
10333 {
10334   switch (p_type)
10335     {
10336     case IPOINTER:
10337     case POINTER:
10338       if (*src=='@')
10339         {
10340           MOVA (src);
10341           emitcode ("mov", "@%s,a", rname);
10342         }
10343       else
10344         emitcode ("mov", "@%s,%s", rname, src);
10345       break;
10346
10347     case PPOINTER:
10348       MOVA (src);
10349       emitcode ("movx", "@%s,a", rname);
10350       break;
10351
10352     case FPOINTER:
10353       MOVA (src);
10354       emitcode ("movx", "@dptr,a");
10355       break;
10356
10357     case GPOINTER:
10358       MOVA (src);
10359       emitcode ("lcall", "__gptrput");
10360       break;
10361     }
10362 }
10363
10364 /*-----------------------------------------------------------------*/
10365 /* genUnpackBits - generates code for unpacking bits               */
10366 /*-----------------------------------------------------------------*/
10367 static void
10368 genUnpackBits (operand * result, char *rname, int ptype)
10369 {
10370   int offset = 0;       /* result byte offset */
10371   int rsize;            /* result size */
10372   int rlen = 0;         /* remaining bitfield length */
10373   sym_link *etype;      /* bitfield type information */
10374   int blen;             /* bitfield length */
10375   int bstr;             /* bitfield starting bit within byte */
10376
10377   D(emitcode (";", "genUnpackBits"));
10378
10379   etype = getSpec (operandType (result));
10380   rsize = getSize (operandType (result));
10381   blen = SPEC_BLEN (etype);
10382   bstr = SPEC_BSTR (etype);
10383
10384   /* If the bitfield length is less than a byte */
10385   if (blen < 8)
10386     {
10387       emitPtrByteGet (rname, ptype, FALSE);
10388       AccRol (8 - bstr);
10389       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
10390       if (!SPEC_USIGN (etype))
10391         {
10392           /* signed bitfield */
10393           symbol *tlbl = newiTempLabel (NULL);
10394
10395           emitcode ("jnb", "acc.%d,%05d$", blen - 1, tlbl->key + 100);
10396           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << blen));
10397           emitLabel (tlbl);
10398         }
10399       aopPut (result, "a", offset++);
10400       goto finish;
10401     }
10402
10403   /* Bit field did not fit in a byte. Copy all
10404      but the partial byte at the end.  */
10405   for (rlen=blen;rlen>=8;rlen-=8)
10406     {
10407       emitPtrByteGet (rname, ptype, FALSE);
10408       aopPut (result, "a", offset++);
10409       if (rlen>8)
10410         emitcode ("inc", "%s", rname);
10411     }
10412
10413   /* Handle the partial byte at the end */
10414   if (rlen)
10415     {
10416       emitPtrByteGet (rname, ptype, FALSE);
10417       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
10418       if (!SPEC_USIGN (etype))
10419         {
10420           /* signed bitfield */
10421           symbol *tlbl = newiTempLabel (NULL);
10422
10423           emitcode ("jnb", "acc.%d,%05d$", rlen - 1, tlbl->key + 100);
10424           emitcode ("orl", "a,#0x%02x", (unsigned char) (0xff << rlen));
10425           emitLabel (tlbl);
10426         }
10427       aopPut (result, "a", offset++);
10428     }
10429
10430 finish:
10431   if (offset < rsize)
10432     {
10433       char *source;
10434
10435       if (SPEC_USIGN (etype))
10436         source = zero;
10437       else
10438         {
10439           /* signed bitfield: sign extension with 0x00 or 0xff */
10440           emitcode ("rlc", "a");
10441           emitcode ("subb", "a,acc");
10442
10443           source = "a";
10444         }
10445       rsize -= offset;
10446       while (rsize--)
10447         aopPut (result, source, offset++);
10448     }
10449 }
10450
10451
10452 /*-----------------------------------------------------------------*/
10453 /* genDataPointerGet - generates code when ptr offset is known     */
10454 /*-----------------------------------------------------------------*/
10455 static void
10456 genDataPointerGet (operand * left,
10457                    operand * result,
10458                    iCode * ic)
10459 {
10460   char *l;
10461   char buffer[256];
10462   int size, offset = 0;
10463   aopOp (result, ic, TRUE, FALSE);
10464
10465   /* get the string representation of the name */
10466   l = aopGet (left, 0, FALSE, TRUE, NULL);
10467   size = AOP_SIZE (result);
10468   _startLazyDPSEvaluation ();
10469   while (size--)
10470     {
10471         if (offset)
10472         {
10473             SNPRINTF (buffer, sizeof(buffer),
10474                       "(%s + %d)", l + 1, offset);
10475         }
10476         else
10477         {
10478             SNPRINTF (buffer, sizeof(buffer),
10479                       "%s", l + 1);
10480         }
10481       aopPut (result, buffer, offset++);
10482     }
10483   _endLazyDPSEvaluation ();
10484
10485   freeAsmop (result, NULL, ic, TRUE);
10486   freeAsmop (left, NULL, ic, TRUE);
10487 }
10488
10489 /*-----------------------------------------------------------------*/
10490 /* genNearPointerGet - emitcode for near pointer fetch             */
10491 /*-----------------------------------------------------------------*/
10492 static void
10493 genNearPointerGet (operand * left,
10494                    operand * result,
10495                    iCode * ic,
10496                    iCode *pi)
10497 {
10498   asmop *aop = NULL;
10499   regs *preg;
10500   char *rname;
10501   sym_link *rtype, *retype, *letype;
10502   sym_link *ltype = operandType (left);
10503   char buffer[80];
10504
10505   rtype = operandType (result);
10506   retype = getSpec (rtype);
10507   letype = getSpec (ltype);
10508
10509   aopOp (left, ic, FALSE, FALSE);
10510
10511   /* if left is rematerialisable and
10512      result is not bitfield variable type and
10513      the left is pointer to data space i.e
10514      lower 128 bytes of space */
10515   if (AOP_TYPE (left) == AOP_IMMD &&
10516       !IS_BITFIELD (retype) &&
10517       !IS_BITFIELD (letype) &&
10518       DCL_TYPE (ltype) == POINTER)
10519     {
10520       genDataPointerGet (left, result, ic);
10521       return;
10522     }
10523
10524   /* if the value is already in a pointer register
10525      then don't need anything more */
10526   if (!AOP_INPREG (AOP (left)))
10527     {
10528       /* otherwise get a free pointer register */
10529       aop = newAsmop (0);
10530       preg = getFreePtr (ic, &aop, FALSE);
10531       emitcode ("mov", "%s,%s",
10532                 preg->name,
10533                 aopGet (left, 0, FALSE, TRUE, DP2_RESULT_REG));
10534       rname = preg->name;
10535     }
10536   else
10537     rname = aopGet (left, 0, FALSE, FALSE, DP2_RESULT_REG);
10538
10539   freeAsmop (left, NULL, ic, TRUE);
10540   aopOp (result, ic, FALSE, FALSE);
10541
10542   /* if bitfield then unpack the bits */
10543   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10544     genUnpackBits (result, rname, POINTER);
10545   else
10546     {
10547       /* we have can just get the values */
10548       int size = AOP_SIZE (result);
10549       int offset = 0;
10550
10551       while (size--)
10552         {
10553           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
10554             {
10555
10556               emitcode ("mov", "a,@%s", rname);
10557               aopPut (result, "a", offset);
10558             }
10559           else
10560             {
10561               SNPRINTF (buffer, sizeof(buffer), "@%s", rname);
10562               aopPut (result, buffer, offset);
10563             }
10564           offset++;
10565           if (size || pi)
10566             emitcode ("inc", "%s", rname);
10567         }
10568     }
10569
10570   /* now some housekeeping stuff */
10571   if (aop)      /* we had to allocate for this iCode */
10572     {
10573       if (pi) { /* post increment present */
10574         aopPut (left, rname, 0);
10575       }
10576       freeAsmop (NULL, aop, ic, TRUE);
10577     }
10578   else
10579     {
10580       /* we did not allocate which means left
10581          already in a pointer register, then
10582          if size > 0 && this could be used again
10583          we have to point it back to where it
10584          belongs */
10585       if (AOP_SIZE (result) > 1 &&
10586           !OP_SYMBOL (left)->remat &&
10587           (OP_SYMBOL (left)->liveTo > ic->seq ||
10588            ic->depth) &&
10589           !pi)
10590         {
10591           int size = AOP_SIZE (result) - 1;
10592           while (size--)
10593             emitcode ("dec", "%s", rname);
10594         }
10595     }
10596
10597   /* done */
10598   freeAsmop (result, NULL, ic, TRUE);
10599   if (pi) pi->generated = 1;
10600 }
10601
10602 /*-----------------------------------------------------------------*/
10603 /* genPagedPointerGet - emitcode for paged pointer fetch           */
10604 /*-----------------------------------------------------------------*/
10605 static void
10606 genPagedPointerGet (operand * left,
10607                     operand * result,
10608                     iCode * ic,
10609                     iCode * pi)
10610 {
10611   asmop *aop = NULL;
10612   regs *preg;
10613   char *rname;
10614   sym_link *rtype, *retype, *letype;
10615
10616   rtype = operandType (result);
10617   retype = getSpec (rtype);
10618   letype = getSpec (operandType (left));
10619   aopOp (left, ic, FALSE, FALSE);
10620
10621   /* if the value is already in a pointer register
10622      then don't need anything more */
10623   if (!AOP_INPREG (AOP (left)))
10624     {
10625       /* otherwise get a free pointer register */
10626       aop = newAsmop (0);
10627       preg = getFreePtr (ic, &aop, FALSE);
10628       emitcode ("mov", "%s,%s",
10629                 preg->name,
10630                 aopGet (left, 0, FALSE, TRUE, NULL));
10631       rname = preg->name;
10632     }
10633   else
10634     rname = aopGet (left, 0, FALSE, FALSE, NULL);
10635
10636   freeAsmop (left, NULL, ic, TRUE);
10637   aopOp (result, ic, FALSE, FALSE);
10638
10639   /* if bitfield then unpack the bits */
10640   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10641     genUnpackBits (result, rname, PPOINTER);
10642   else
10643     {
10644       /* we have can just get the values */
10645       int size = AOP_SIZE (result);
10646       int offset = 0;
10647
10648       while (size--)
10649         {
10650
10651           emitcode ("movx", "a,@%s", rname);
10652           aopPut (result, "a", offset);
10653
10654           offset++;
10655
10656           if (size || pi)
10657             emitcode ("inc", "%s", rname);
10658         }
10659     }
10660
10661   /* now some housekeeping stuff */
10662   if (aop)      /* we had to allocate for this iCode */
10663     {
10664       if (pi)
10665         aopPut (left, rname, 0);
10666       freeAsmop (NULL, aop, ic, TRUE);
10667     }
10668   else
10669     {
10670       /* we did not allocate which means left
10671          already in a pointer register, then
10672          if size > 0 && this could be used again
10673          we have to point it back to where it
10674          belongs */
10675       if (AOP_SIZE (result) > 1 &&
10676           !OP_SYMBOL (left)->remat &&
10677           (OP_SYMBOL (left)->liveTo > ic->seq ||
10678            ic->depth) &&
10679           !pi)
10680         {
10681           int size = AOP_SIZE (result) - 1;
10682           while (size--)
10683             emitcode ("dec", "%s", rname);
10684         }
10685     }
10686
10687   /* done */
10688   freeAsmop (result, NULL, ic, TRUE);
10689   if (pi) pi->generated = 1;
10690 }
10691
10692 /*-----------------------------------------------------------------*/
10693 /* genFarPointerGet - get value from far space                     */
10694 /*-----------------------------------------------------------------*/
10695 static void
10696 genFarPointerGet (operand * left,
10697                   operand * result, iCode * ic, iCode *pi)
10698 {
10699   int size, offset, dopi=1;
10700   sym_link *retype = getSpec (operandType (result));
10701   sym_link *letype = getSpec (operandType (left));
10702   D (emitcode (";", "genFarPointerGet"););
10703
10704   aopOp (left, ic, FALSE, FALSE);
10705
10706   /* if the operand is already in dptr
10707      then we do nothing else we move the value to dptr */
10708   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
10709     {
10710       /* if this is rematerializable */
10711       if (AOP_TYPE (left) == AOP_IMMD)
10712         {
10713           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10714         }
10715       else
10716         {
10717           /* we need to get it byte by byte */
10718           _startLazyDPSEvaluation ();
10719           if (AOP_TYPE (left) != AOP_DPTR)
10720             {
10721               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10722               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10723               if (options.model == MODEL_FLAT24)
10724                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10725             }
10726           else
10727             {
10728               /* We need to generate a load to DPTR indirect through DPTR. */
10729               D (emitcode (";", "genFarPointerGet -- indirection special case."););
10730               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10731               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10732               if (options.model == MODEL_FLAT24)
10733                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10734               emitcode ("pop", "dph");
10735               emitcode ("pop", "dpl");
10736               dopi =0;
10737             }
10738           _endLazyDPSEvaluation ();
10739         }
10740     }
10741   /* so dptr now contains the address */
10742   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10743
10744   /* if bit then unpack */
10745   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10746       if (AOP_INDPTRn(left)) {
10747           genSetDPTR(AOP(left)->aopu.dptr);
10748       }
10749       genUnpackBits (result, "dptr", FPOINTER);
10750       if (AOP_INDPTRn(left)) {
10751           genSetDPTR(0);
10752       }
10753   } else
10754     {
10755       size = AOP_SIZE (result);
10756       offset = 0;
10757
10758       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10759           while (size--) {
10760               genSetDPTR(AOP(left)->aopu.dptr);
10761               emitcode ("movx", "a,@dptr");
10762               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10763                   emitcode ("inc", "dptr");
10764               genSetDPTR (0);
10765               aopPut (result, "a", offset++);
10766           }
10767       } else {
10768           _startLazyDPSEvaluation ();
10769           while (size--) {
10770               if (AOP_INDPTRn(left)) {
10771                   genSetDPTR(AOP(left)->aopu.dptr);
10772               } else {
10773                   genSetDPTR (0);
10774               }
10775               _flushLazyDPS ();
10776
10777               emitcode ("movx", "a,@dptr");
10778               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10779                   emitcode ("inc", "dptr");
10780
10781               aopPut (result, "a", offset++);
10782           }
10783           _endLazyDPSEvaluation ();
10784       }
10785     }
10786   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10787       if (!AOP_INDPTRn(left)) {
10788           _startLazyDPSEvaluation ();
10789           aopPut (left, "dpl", 0);
10790           aopPut (left, "dph", 1);
10791           if (options.model == MODEL_FLAT24)
10792               aopPut (left, "dpx", 2);
10793           _endLazyDPSEvaluation ();
10794       }
10795     pi->generated = 1;
10796   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10797              AOP_SIZE(result) > 1 &&
10798              IS_SYMOP(left) &&
10799              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10800
10801       size = AOP_SIZE (result) - 1;
10802       if (AOP_INDPTRn(left)) {
10803           genSetDPTR(AOP(left)->aopu.dptr);
10804       }
10805       while (size--) emitcode ("lcall","__decdptr");
10806       if (AOP_INDPTRn(left)) {
10807           genSetDPTR(0);
10808       }
10809   }
10810
10811   freeAsmop (result, NULL, ic, TRUE);
10812   freeAsmop (left, NULL, ic, TRUE);
10813 }
10814
10815 /*-----------------------------------------------------------------*/
10816 /* genCodePointerGet - get value from code space                   */
10817 /*-----------------------------------------------------------------*/
10818 static void
10819 genCodePointerGet (operand * left,
10820                     operand * result, iCode * ic, iCode *pi)
10821 {
10822   int size, offset, dopi=1;
10823   sym_link *retype = getSpec (operandType (result));
10824
10825   aopOp (left, ic, FALSE, FALSE);
10826
10827   /* if the operand is already in dptr
10828      then we do nothing else we move the value to dptr */
10829   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10830     {
10831       /* if this is rematerializable */
10832       if (AOP_TYPE (left) == AOP_IMMD)
10833         {
10834           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10835         }
10836       else
10837         {                       /* we need to get it byte by byte */
10838           _startLazyDPSEvaluation ();
10839           if (AOP_TYPE (left) != AOP_DPTR)
10840             {
10841               emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
10842               emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
10843               if (options.model == MODEL_FLAT24)
10844                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10845             }
10846           else
10847             {
10848               /* We need to generate a load to DPTR indirect through DPTR. */
10849               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10850               emitcode ("push", "%s", aopGet (left, 0, FALSE, TRUE, NULL));
10851               emitcode ("push", "%s", aopGet (left, 1, FALSE, TRUE, NULL));
10852               if (options.model == MODEL_FLAT24)
10853                 emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
10854               emitcode ("pop", "dph");
10855               emitcode ("pop", "dpl");
10856               dopi=0;
10857             }
10858           _endLazyDPSEvaluation ();
10859         }
10860     }
10861   /* so dptr now contains the address */
10862   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10863
10864   /* if bit then unpack */
10865   if (IS_BITFIELD (retype)) {
10866       if (AOP_INDPTRn(left)) {
10867           genSetDPTR(AOP(left)->aopu.dptr);
10868       }
10869       genUnpackBits (result, "dptr", CPOINTER);
10870       if (AOP_INDPTRn(left)) {
10871           genSetDPTR(0);
10872       }
10873   } else
10874     {
10875       size = AOP_SIZE (result);
10876       offset = 0;
10877       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10878           while (size--) {
10879               genSetDPTR(AOP(left)->aopu.dptr);
10880               emitcode ("clr", "a");
10881               emitcode ("movc", "a,@a+dptr");
10882               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10883                   emitcode ("inc", "dptr");
10884               genSetDPTR (0);
10885               aopPut (result, "a", offset++);
10886           }
10887       } else {
10888           _startLazyDPSEvaluation ();
10889           while (size--)
10890               {
10891                   if (AOP_INDPTRn(left)) {
10892                       genSetDPTR(AOP(left)->aopu.dptr);
10893                   } else {
10894                       genSetDPTR (0);
10895                   }
10896                   _flushLazyDPS ();
10897
10898                   emitcode ("clr", "a");
10899                   emitcode ("movc", "a,@a+dptr");
10900                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10901                       emitcode ("inc", "dptr");
10902                   aopPut (result, "a", offset++);
10903               }
10904           _endLazyDPSEvaluation ();
10905       }
10906     }
10907   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10908       if (!AOP_INDPTRn(left)) {
10909           _startLazyDPSEvaluation ();
10910
10911           aopPut (left, "dpl", 0);
10912           aopPut (left, "dph", 1);
10913           if (options.model == MODEL_FLAT24)
10914               aopPut (left, "dpx", 2);
10915
10916           _endLazyDPSEvaluation ();
10917       }
10918       pi->generated = 1;
10919   } else if (IS_SYMOP(left) &&
10920              (OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10921              AOP_SIZE(result) > 1 &&
10922              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10923
10924       size = AOP_SIZE (result) - 1;
10925       if (AOP_INDPTRn(left)) {
10926           genSetDPTR(AOP(left)->aopu.dptr);
10927       }
10928       while (size--) emitcode ("lcall","__decdptr");
10929       if (AOP_INDPTRn(left)) {
10930           genSetDPTR(0);
10931       }
10932   }
10933
10934   freeAsmop (result, NULL, ic, TRUE);
10935   freeAsmop (left, NULL, ic, TRUE);
10936 }
10937
10938 /*-----------------------------------------------------------------*/
10939 /* genGenPointerGet - get value from generic pointer space         */
10940 /*-----------------------------------------------------------------*/
10941 static void
10942 genGenPointerGet (operand * left,
10943                   operand * result, iCode * ic, iCode * pi)
10944 {
10945   int size, offset;
10946   bool pushedB;
10947   sym_link *retype = getSpec (operandType (result));
10948   sym_link *letype = getSpec (operandType (left));
10949
10950   D (emitcode (";", "genGenPointerGet"));
10951
10952   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10953
10954   pushedB = pushB ();
10955   /* if the operand is already in dptr
10956      then we do nothing else we move the value to dptr */
10957   if (AOP_TYPE (left) != AOP_STR)
10958     {
10959       /* if this is rematerializable */
10960       if (AOP_TYPE (left) == AOP_IMMD)
10961         {
10962           emitcode ("mov", "dptr,%s", aopGet (left, 0, TRUE, FALSE, NULL));
10963           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10964             {
10965               MOVB (aopGet (left, AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10966             }
10967           else
10968             {
10969               emitcode ("mov", "b,#%d", pointerCode (retype));
10970             }
10971         }
10972       else
10973         {                       /* we need to get it byte by byte */
10974           _startLazyDPSEvaluation ();
10975           emitcode ("mov", "dpl,%s", aopGet (left,0,FALSE,FALSE,NULL));
10976           emitcode ("mov", "dph,%s", aopGet (left,1,FALSE,FALSE,NULL));
10977           if (options.model == MODEL_FLAT24) {
10978               emitcode ("mov", "dpx,%s", aopGet (left,2,FALSE,FALSE,NULL));
10979               emitcode ("mov", "b,%s", aopGet (left,3,FALSE,FALSE,NULL));
10980           } else {
10981               emitcode ("mov", "b,%s", aopGet (left,2,FALSE,FALSE,NULL));
10982           }
10983           _endLazyDPSEvaluation ();
10984         }
10985     }
10986
10987   /* so dptr-b now contains the address */
10988   aopOp (result, ic, FALSE, TRUE);
10989
10990   /* if bit then unpack */
10991   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10992   {
10993     genUnpackBits (result, "dptr", GPOINTER);
10994   }
10995   else
10996     {
10997         size = AOP_SIZE (result);
10998         offset = 0;
10999
11000         while (size--)
11001         {
11002             if (size)
11003             {
11004                 // Get two bytes at a time, results in _AP & A.
11005                 // dptr will be incremented ONCE by __gptrgetWord.
11006                 //
11007                 // Note: any change here must be coordinated
11008                 // with the implementation of __gptrgetWord
11009                 // in device/lib/_gptrget.c
11010                 emitcode ("lcall", "__gptrgetWord");
11011                 aopPut (result, "a", offset++);
11012                 aopPut (result, DP2_RESULT_REG, offset++);
11013                 size--;
11014             }
11015             else
11016             {
11017                 // Only one byte to get.
11018                 emitcode ("lcall", "__gptrget");
11019                 aopPut (result, "a", offset++);
11020             }
11021
11022             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
11023             {
11024                 emitcode ("inc", "dptr");
11025             }
11026         }
11027     }
11028
11029   if (pi && AOP_TYPE (left) != AOP_IMMD) {
11030     _startLazyDPSEvaluation ();
11031
11032     aopPut (left, "dpl", 0);
11033     aopPut (left, "dph", 1);
11034     if (options.model == MODEL_FLAT24) {
11035         aopPut (left, "dpx", 2);
11036         aopPut (left, "b", 3);
11037     } else  aopPut (left, "b", 2);
11038
11039     _endLazyDPSEvaluation ();
11040
11041     pi->generated = 1;
11042   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
11043              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
11044
11045       size = AOP_SIZE (result) - 1;
11046       while (size--) emitcode ("lcall","__decdptr");
11047   }
11048   popB (pushedB);
11049
11050   freeAsmop (result, NULL, ic, TRUE);
11051   freeAsmop (left, NULL, ic, TRUE);
11052 }
11053
11054 /*-----------------------------------------------------------------*/
11055 /* genPointerGet - generate code for pointer get                   */
11056 /*-----------------------------------------------------------------*/
11057 static void
11058 genPointerGet (iCode * ic, iCode *pi)
11059 {
11060   operand *left, *result;
11061   sym_link *type, *etype;
11062   int p_type;
11063
11064   D (emitcode (";", "genPointerGet"));
11065
11066   left = IC_LEFT (ic);
11067   result = IC_RESULT (ic);
11068
11069   /* depending on the type of pointer we need to
11070      move it to the correct pointer register */
11071   type = operandType (left);
11072   etype = getSpec (type);
11073   /* if left is of type of pointer then it is simple */
11074   if (IS_PTR (type) && !IS_FUNC (type->next))
11075     p_type = DCL_TYPE (type);
11076   else
11077     {
11078       /* we have to go by the storage class */
11079       p_type = PTR_TYPE (SPEC_OCLS (etype));
11080     }
11081
11082   /* special case when cast remat */
11083   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
11084       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
11085     {
11086       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
11087       type = operandType (left);
11088       p_type = DCL_TYPE (type);
11089     }
11090   /* now that we have the pointer type we assign
11091      the pointer values */
11092   switch (p_type)
11093     {
11094
11095     case POINTER:
11096     case IPOINTER:
11097       genNearPointerGet (left, result, ic, pi);
11098       break;
11099
11100     case PPOINTER:
11101       genPagedPointerGet (left, result, ic, pi);
11102       break;
11103
11104     case FPOINTER:
11105       genFarPointerGet (left, result, ic, pi);
11106       break;
11107
11108     case CPOINTER:
11109       genCodePointerGet (left, result, ic, pi);
11110       break;
11111
11112     case GPOINTER:
11113       genGenPointerGet (left, result, ic, pi);
11114       break;
11115     }
11116 }
11117
11118
11119 /*-----------------------------------------------------------------*/
11120 /* genPackBits - generates code for packed bit storage             */
11121 /*-----------------------------------------------------------------*/
11122 static void
11123 genPackBits (sym_link * etype,
11124              operand * right,
11125              char *rname, int p_type)
11126 {
11127   int offset = 0;       /* source byte offset */
11128   int rlen = 0;         /* remaining bitfield length */
11129   int blen;             /* bitfield length */
11130   int bstr;             /* bitfield starting bit within byte */
11131   int litval;           /* source literal value (if AOP_LIT) */
11132   unsigned char mask;   /* bitmask within current byte */
11133
11134   D(emitcode (";", "genPackBits"));
11135
11136   blen = SPEC_BLEN (etype);
11137   bstr = SPEC_BSTR (etype);
11138
11139   /* If the bitfield length is less than a byte */
11140   if (blen < 8)
11141     {
11142       mask = ((unsigned char) (0xFF << (blen + bstr)) |
11143               (unsigned char) (0xFF >> (8 - bstr)));
11144
11145       if (AOP_TYPE (right) == AOP_LIT)
11146         {
11147           /* Case with a bitfield length <8 and literal source
11148           */
11149           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11150           litval <<= bstr;
11151           litval &= (~mask) & 0xff;
11152           emitPtrByteGet (rname, p_type, FALSE);
11153           if ((mask|litval)!=0xff)
11154             emitcode ("anl","a,#!constbyte", mask);
11155           if (litval)
11156             emitcode ("orl","a,#!constbyte", litval);
11157         }
11158       else
11159         {
11160           if ((blen==1) && (p_type!=GPOINTER))
11161             {
11162               /* Case with a bitfield length == 1 and no generic pointer
11163               */
11164               if (AOP_TYPE (right) == AOP_CRY)
11165                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
11166               else
11167                 {
11168                   MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11169                   emitcode ("rrc","a");
11170                 }
11171               emitPtrByteGet (rname, p_type, FALSE);
11172               emitcode ("mov","acc.%d,c",bstr);
11173             }
11174           else
11175             {
11176               bool pushedB;
11177               /* Case with a bitfield length < 8 and arbitrary source
11178               */
11179               MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
11180               /* shift and mask source value */
11181               AccLsh (bstr);
11182               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11183
11184               pushedB = pushB ();
11185               /* transfer A to B and get next byte */
11186               emitPtrByteGet (rname, p_type, TRUE);
11187
11188               emitcode ("anl", "a,#!constbyte", mask);
11189               emitcode ("orl", "a,b");
11190               if (p_type == GPOINTER)
11191                 emitcode ("pop", "b");
11192
11193               popB (pushedB);
11194            }
11195         }
11196
11197       emitPtrByteSet (rname, p_type, "a");
11198       return;
11199     }
11200
11201   /* Bit length is greater than 7 bits. In this case, copy  */
11202   /* all except the partial byte at the end                 */
11203   for (rlen=blen;rlen>=8;rlen-=8)
11204     {
11205       emitPtrByteSet (rname, p_type,
11206                       aopGet (right, offset++, FALSE, TRUE, NULL) );
11207       if (rlen>8)
11208         emitcode ("inc", "%s", rname);
11209     }
11210
11211   /* If there was a partial byte at the end */
11212   if (rlen)
11213     {
11214       mask = (((unsigned char) -1 << rlen) & 0xff);
11215
11216       if (AOP_TYPE (right) == AOP_LIT)
11217         {
11218           /* Case with partial byte and literal source
11219           */
11220           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
11221           litval >>= (blen-rlen);
11222           litval &= (~mask) & 0xff;
11223           emitPtrByteGet (rname, p_type, FALSE);
11224           if ((mask|litval)!=0xff)
11225             emitcode ("anl","a,#!constbyte", mask);
11226           if (litval)
11227             emitcode ("orl","a,#!constbyte", litval);
11228         }
11229       else
11230         {
11231           bool pushedB;
11232           /* Case with partial byte and arbitrary source
11233           */
11234           MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11235           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
11236
11237           pushedB = pushB ();
11238           /* transfer A to B and get next byte */
11239           emitPtrByteGet (rname, p_type, TRUE);
11240
11241           emitcode ("anl", "a,#!constbyte", mask);
11242           emitcode ("orl", "a,b");
11243           if (p_type == GPOINTER)
11244             emitcode ("pop", "b");
11245
11246           popB (pushedB);
11247         }
11248       emitPtrByteSet (rname, p_type, "a");
11249     }
11250 }
11251
11252
11253 /*-----------------------------------------------------------------*/
11254 /* genDataPointerSet - remat pointer to data space                 */
11255 /*-----------------------------------------------------------------*/
11256 static void
11257 genDataPointerSet (operand * right,
11258                    operand * result,
11259                    iCode * ic)
11260 {
11261   int size, offset = 0;
11262   char *l, buffer[256];
11263
11264   D (emitcode (";", "genDataPointerSet"));
11265
11266   aopOp (right, ic, FALSE, FALSE);
11267
11268   l = aopGet (result, 0, FALSE, TRUE, NULL);
11269   size = AOP_SIZE (right);
11270   while (size--)
11271     {
11272       if (offset)
11273           SNPRINTF (buffer, sizeof(buffer), "(%s + %d)", l + 1, offset);
11274       else
11275           SNPRINTF (buffer, sizeof(buffer), "%s", l + 1);
11276       emitcode ("mov", "%s,%s", buffer,
11277                 aopGet (right, offset++, FALSE, FALSE, NULL));
11278     }
11279
11280   freeAsmop (result, NULL, ic, TRUE);
11281   freeAsmop (right, NULL, ic, TRUE);
11282 }
11283
11284 /*-----------------------------------------------------------------*/
11285 /* genNearPointerSet - emitcode for near pointer put                */
11286 /*-----------------------------------------------------------------*/
11287 static void
11288 genNearPointerSet (operand * right,
11289                    operand * result,
11290                    iCode * ic,
11291                    iCode * pi)
11292 {
11293   asmop *aop = NULL;
11294   char *rname, *l;
11295   sym_link *retype, *letype;
11296   sym_link *ptype = operandType (result);
11297
11298   D (emitcode (";", "genNearPointerSet"));
11299
11300   retype = getSpec (operandType (right));
11301   letype = getSpec (ptype);
11302
11303   aopOp (result, ic, FALSE, FALSE);
11304
11305   /* if the result is rematerializable &
11306      in data space & not a bit variable */
11307   if (AOP_TYPE (result) == AOP_IMMD &&
11308       DCL_TYPE (ptype) == POINTER &&
11309       !IS_BITVAR (retype) &&
11310       !IS_BITVAR (letype))
11311     {
11312       genDataPointerSet (right, result, ic);
11313       return;
11314     }
11315
11316   /* if the value is already in a pointer register
11317      then don't need anything more */
11318   if (!AOP_INPREG (AOP (result)))
11319     {
11320       /* otherwise get a free pointer register */
11321       regs *preg;
11322
11323       aop = newAsmop (0);
11324       preg = getFreePtr (ic, &aop, FALSE);
11325       emitcode ("mov", "%s,%s",
11326                 preg->name,
11327                 aopGet (result, 0, FALSE, TRUE, NULL));
11328       rname = preg->name;
11329     }
11330   else
11331     {
11332       rname = aopGet (result, 0, FALSE, FALSE, NULL);
11333     }
11334
11335   aopOp (right, ic, FALSE, FALSE);
11336
11337   /* if bitfield then unpack the bits */
11338   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11339     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
11340   else
11341     {
11342       /* we can just get the values */
11343       int size = AOP_SIZE (right);
11344       int offset = 0;
11345
11346       while (size--)
11347         {
11348           l = aopGet (right, offset, FALSE, TRUE, NULL);
11349           if ((*l == '@') || (strcmp (l, "acc") == 0))
11350             {
11351               MOVA (l);
11352               emitcode ("mov", "@%s,a", rname);
11353             }
11354           else
11355             emitcode ("mov", "@%s,%s", rname, l);
11356           if (size || pi)
11357             emitcode ("inc", "%s", rname);
11358           offset++;
11359         }
11360     }
11361
11362   /* now some housekeeping stuff */
11363   if (aop)      /* we had to allocate for this iCode */
11364     {
11365       if (pi)
11366         aopPut (result, rname, 0);
11367       freeAsmop (NULL, aop, ic, TRUE);
11368     }
11369   else
11370     {
11371       /* we did not allocate which means left
11372          already in a pointer register, then
11373          if size > 0 && this could be used again
11374          we have to point it back to where it
11375          belongs */
11376       if (AOP_SIZE (right) > 1 &&
11377           !OP_SYMBOL (result)->remat &&
11378           (OP_SYMBOL (result)->liveTo > ic->seq ||
11379            ic->depth) &&
11380           !pi)
11381         {
11382           int size = AOP_SIZE (right) - 1;
11383           while (size--)
11384             emitcode ("dec", "%s", rname);
11385         }
11386     }
11387
11388   /* done */
11389   if (pi) pi->generated = 1;
11390   freeAsmop (result, NULL, ic, TRUE);
11391   freeAsmop (right, NULL, ic, TRUE);
11392 }
11393
11394 /*-----------------------------------------------------------------*/
11395 /* genPagedPointerSet - emitcode for Paged pointer put             */
11396 /*-----------------------------------------------------------------*/
11397 static void
11398 genPagedPointerSet (operand * right,
11399                     operand * result,
11400                     iCode * ic,
11401                     iCode *pi)
11402 {
11403   asmop *aop = NULL;
11404   char *rname, *l;
11405   sym_link *retype, *letype;
11406
11407   D (emitcode (";", "genPagedPointerSet"));
11408
11409   retype = getSpec (operandType (right));
11410   letype = getSpec (operandType (result));
11411
11412   aopOp (result, ic, FALSE, FALSE);
11413
11414   /* if the value is already in a pointer register
11415      then don't need anything more */
11416   if (!AOP_INPREG (AOP (result)))
11417     {
11418       /* otherwise get a free pointer register */
11419       regs *preg;
11420
11421       aop = newAsmop (0);
11422       preg = getFreePtr (ic, &aop, FALSE);
11423       emitcode ("mov", "%s,%s",
11424                 preg->name,
11425                 aopGet (result, 0, FALSE, TRUE, NULL));
11426       rname = preg->name;
11427     }
11428   else
11429     rname = aopGet (result, 0, FALSE, FALSE, NULL);
11430
11431   aopOp (right, ic, FALSE, FALSE);
11432
11433   /* if bitfield then unpack the bits */
11434   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11435     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
11436   else
11437     {
11438       /* we have can just get the values */
11439       int size = AOP_SIZE (right);
11440       int offset = 0;
11441
11442       while (size--)
11443         {
11444           l = aopGet (right, offset, FALSE, TRUE, NULL);
11445           MOVA (l);
11446           emitcode ("movx", "@%s,a", rname);
11447
11448           if (size || pi)
11449             emitcode ("inc", "%s", rname);
11450
11451           offset++;
11452         }
11453     }
11454
11455   /* now some housekeeping stuff */
11456   if (aop)
11457     {
11458       if (pi)
11459         aopPut (result, rname, 0);
11460       /* we had to allocate for this iCode */
11461       freeAsmop (NULL, aop, ic, TRUE);
11462     }
11463   else
11464     {
11465       /* we did not allocate which means left
11466          already in a pointer register, then
11467          if size > 0 && this could be used again
11468          we have to point it back to where it
11469          belongs */
11470       if (AOP_SIZE (right) > 1 &&
11471           !OP_SYMBOL (result)->remat &&
11472           (OP_SYMBOL (result)->liveTo > ic->seq ||
11473            ic->depth) &&
11474           !pi)
11475         {
11476           int size = AOP_SIZE (right) - 1;
11477           while (size--)
11478             emitcode ("dec", "%s", rname);
11479         }
11480     }
11481
11482   /* done */
11483   if (pi) pi->generated = 1;
11484   freeAsmop (result, NULL, ic, TRUE);
11485   freeAsmop (right, NULL, ic, TRUE);
11486 }
11487
11488 /*-----------------------------------------------------------------*/
11489 /* genFarPointerSet - set value from far space                     */
11490 /*-----------------------------------------------------------------*/
11491 static void
11492 genFarPointerSet (operand * right,
11493                   operand * result, iCode * ic, iCode *pi)
11494 {
11495   int size, offset, dopi=1;
11496   sym_link *retype = getSpec (operandType (right));
11497   sym_link *letype = getSpec (operandType (result));
11498
11499   aopOp (result, ic, FALSE, FALSE);
11500
11501   /* if the operand is already in dptr
11502      then we do nothing else we move the value to dptr */
11503   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
11504     {
11505       /* if this is remateriazable */
11506       if (AOP_TYPE (result) == AOP_IMMD)
11507         emitcode ("mov", "dptr,%s",
11508                   aopGet (result, 0, TRUE, FALSE, NULL));
11509       else
11510         {
11511           /* we need to get it byte by byte */
11512           _startLazyDPSEvaluation ();
11513           if (AOP_TYPE (result) != AOP_DPTR)
11514             {
11515               emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11516               emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11517               if (options.model == MODEL_FLAT24)
11518                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11519             }
11520           else
11521             {
11522               /* We need to generate a load to DPTR indirect through DPTR. */
11523               D (emitcode (";", "genFarPointerSet -- indirection special case."););
11524
11525               emitcode ("push", "%s", aopGet (result, 0, FALSE, TRUE, NULL));
11526               emitcode ("push", "%s", aopGet (result, 1, FALSE, TRUE, NULL));
11527               if (options.model == MODEL_FLAT24)
11528                 emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11529               emitcode ("pop", "dph");
11530               emitcode ("pop", "dpl");
11531               dopi=0;
11532             }
11533           _endLazyDPSEvaluation ();
11534         }
11535     }
11536   /* so dptr now contains the address */
11537   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
11538
11539   /* if bit then unpack */
11540   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11541   {
11542       if (AOP_INDPTRn(result)) {
11543           genSetDPTR(AOP(result)->aopu.dptr);
11544       }
11545       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
11546       if (AOP_INDPTRn(result)) {
11547           genSetDPTR(0);
11548       }
11549   } else {
11550       size = AOP_SIZE (right);
11551       offset = 0;
11552       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
11553           while (size--) {
11554               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11555
11556               genSetDPTR(AOP(result)->aopu.dptr);
11557               emitcode ("movx", "@dptr,a");
11558               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11559                   emitcode ("inc", "dptr");
11560               genSetDPTR (0);
11561           }
11562       } else {
11563           _startLazyDPSEvaluation ();
11564           while (size--) {
11565               MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11566
11567               if (AOP_INDPTRn(result)) {
11568                   genSetDPTR(AOP(result)->aopu.dptr);
11569               } else {
11570                   genSetDPTR (0);
11571               }
11572               _flushLazyDPS ();
11573
11574               emitcode ("movx", "@dptr,a");
11575               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
11576                   emitcode ("inc", "dptr");
11577           }
11578           _endLazyDPSEvaluation ();
11579       }
11580   }
11581
11582   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
11583       if (!AOP_INDPTRn(result)) {
11584           _startLazyDPSEvaluation ();
11585
11586           aopPut (result,"dpl",0);
11587           aopPut (result,"dph",1);
11588           if (options.model == MODEL_FLAT24)
11589               aopPut (result,"dpx",2);
11590
11591           _endLazyDPSEvaluation ();
11592       }
11593       pi->generated=1;
11594   } else if (IS_SYMOP (result) &&
11595              (OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
11596              AOP_SIZE(right) > 1 &&
11597              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11598
11599       size = AOP_SIZE (right) - 1;
11600       if (AOP_INDPTRn(result)) {
11601           genSetDPTR(AOP(result)->aopu.dptr);
11602       }
11603       while (size--) emitcode ("lcall","__decdptr");
11604       if (AOP_INDPTRn(result)) {
11605           genSetDPTR(0);
11606       }
11607   }
11608   freeAsmop (result, NULL, ic, TRUE);
11609   freeAsmop (right, NULL, ic, TRUE);
11610 }
11611
11612 /*-----------------------------------------------------------------*/
11613 /* genGenPointerSet - set value from generic pointer space         */
11614 /*-----------------------------------------------------------------*/
11615 static void
11616 genGenPointerSet (operand * right,
11617                   operand * result, iCode * ic, iCode *pi)
11618 {
11619   int size, offset;
11620   bool pushedB;
11621   sym_link *retype = getSpec (operandType (right));
11622   sym_link *letype = getSpec (operandType (result));
11623
11624   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
11625
11626   pushedB = pushB ();
11627   /* if the operand is already in dptr
11628      then we do nothing else we move the value to dptr */
11629   if (AOP_TYPE (result) != AOP_STR)
11630     {
11631       _startLazyDPSEvaluation ();
11632       /* if this is remateriazable */
11633       if (AOP_TYPE (result) == AOP_IMMD)
11634         {
11635           emitcode ("mov", "dptr,%s", aopGet (result, 0, TRUE, FALSE, NULL));
11636           if (AOP(result)->aopu.aop_immd.from_cast_remat)
11637           {
11638               MOVB (aopGet (result, AOP_SIZE(result)-1, FALSE, FALSE, NULL));
11639           }
11640           else
11641           {
11642               emitcode ("mov",
11643                         "b,%s + 1", aopGet (result, 0, TRUE, FALSE, NULL));
11644           }
11645         }
11646       else
11647         {                       /* we need to get it byte by byte */
11648           emitcode ("mov", "dpl,%s", aopGet (result, 0, FALSE, FALSE, NULL));
11649           emitcode ("mov", "dph,%s", aopGet (result, 1, FALSE, FALSE, NULL));
11650           if (options.model == MODEL_FLAT24) {
11651             emitcode ("mov", "dpx,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11652             emitcode ("mov", "b,%s", aopGet (result, 3, FALSE, FALSE, NULL));
11653           } else {
11654             emitcode ("mov", "b,%s", aopGet (result, 2, FALSE, FALSE, NULL));
11655           }
11656         }
11657       _endLazyDPSEvaluation ();
11658     }
11659   /* so dptr + b now contains the address */
11660   aopOp (right, ic, FALSE, TRUE);
11661
11662   /* if bit then unpack */
11663   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
11664     {
11665         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
11666     }
11667   else
11668     {
11669         size = AOP_SIZE (right);
11670         offset = 0;
11671
11672         _startLazyDPSEvaluation ();
11673         while (size--)
11674         {
11675             if (size)
11676             {
11677                 // Set two bytes at a time, passed in _AP & A.
11678                 // dptr will be incremented ONCE by __gptrputWord.
11679                 //
11680                 // Note: any change here must be coordinated
11681                 // with the implementation of __gptrputWord
11682                 // in device/lib/_gptrput.c
11683                 emitcode("mov", "_ap, %s",
11684                          aopGet (right, offset++, FALSE, FALSE, NULL));
11685                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11686
11687                 genSetDPTR (0);
11688                 _flushLazyDPS ();
11689                 emitcode ("lcall", "__gptrputWord");
11690                 size--;
11691             }
11692             else
11693             {
11694                 // Only one byte to put.
11695                 MOVA (aopGet (right, offset++, FALSE, FALSE, NULL));
11696
11697                 genSetDPTR (0);
11698                 _flushLazyDPS ();
11699                 emitcode ("lcall", "__gptrput");
11700             }
11701
11702             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
11703             {
11704                 emitcode ("inc", "dptr");
11705             }
11706         }
11707         _endLazyDPSEvaluation ();
11708     }
11709
11710   if (pi && AOP_TYPE (result) != AOP_IMMD) {
11711       _startLazyDPSEvaluation ();
11712
11713       aopPut (result, "dpl",0);
11714       aopPut (result, "dph",1);
11715       if (options.model == MODEL_FLAT24) {
11716           aopPut (result, "dpx",2);
11717           aopPut (result, "b",3);
11718       } else {
11719           aopPut (result, "b",2);
11720       }
11721       _endLazyDPSEvaluation ();
11722
11723       pi->generated=1;
11724   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
11725              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
11726
11727       size = AOP_SIZE (right) - 1;
11728       while (size--) emitcode ("lcall","__decdptr");
11729   }
11730   popB (pushedB);
11731
11732   freeAsmop (result, NULL, ic, TRUE);
11733   freeAsmop (right, NULL, ic, TRUE);
11734 }
11735
11736 /*-----------------------------------------------------------------*/
11737 /* genPointerSet - stores the value into a pointer location        */
11738 /*-----------------------------------------------------------------*/
11739 static void
11740 genPointerSet (iCode * ic, iCode *pi)
11741 {
11742   operand *right, *result;
11743   sym_link *type, *etype;
11744   int p_type;
11745
11746   D (emitcode (";", "genPointerSet"));
11747
11748   right = IC_RIGHT (ic);
11749   result = IC_RESULT (ic);
11750
11751   /* depending on the type of pointer we need to
11752      move it to the correct pointer register */
11753   type = operandType (result);
11754   etype = getSpec (type);
11755   /* if left is of type of pointer then it is simple */
11756   if (IS_PTR (type) && !IS_FUNC (type->next))
11757     {
11758       p_type = DCL_TYPE (type);
11759     }
11760   else
11761     {
11762       /* we have to go by the storage class */
11763       p_type = PTR_TYPE (SPEC_OCLS (etype));
11764     }
11765
11766   /* special case when cast remat */
11767   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
11768       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
11769           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
11770           type = operandType (result);
11771           p_type = DCL_TYPE (type);
11772   }
11773
11774   /* now that we have the pointer type we assign
11775      the pointer values */
11776   switch (p_type)
11777     {
11778
11779     case POINTER:
11780     case IPOINTER:
11781       genNearPointerSet (right, result, ic, pi);
11782       break;
11783
11784     case PPOINTER:
11785       genPagedPointerSet (right, result, ic, pi);
11786       break;
11787
11788     case FPOINTER:
11789       genFarPointerSet (right, result, ic, pi);
11790       break;
11791
11792     case GPOINTER:
11793       genGenPointerSet (right, result, ic, pi);
11794       break;
11795
11796     default:
11797       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11798               "genPointerSet: illegal pointer type");
11799     }
11800 }
11801
11802 /*-----------------------------------------------------------------*/
11803 /* genIfx - generate code for Ifx statement                        */
11804 /*-----------------------------------------------------------------*/
11805 static void
11806 genIfx (iCode * ic, iCode * popIc)
11807 {
11808   operand *cond = IC_COND (ic);
11809   int isbit = 0;
11810   char *dup = NULL;
11811
11812   D (emitcode (";", "genIfx"));
11813
11814   aopOp (cond, ic, FALSE, FALSE);
11815
11816   /* get the value into acc */
11817   if (AOP_TYPE (cond) != AOP_CRY)
11818     {
11819       toBoolean (cond);
11820     }
11821   else
11822     {
11823       isbit = 1;
11824       if (AOP(cond)->aopu.aop_dir)
11825         dup = Safe_strdup(AOP(cond)->aopu.aop_dir);
11826     }
11827
11828   /* the result is now in the accumulator or a directly addressable bit */
11829   freeAsmop (cond, NULL, ic, TRUE);
11830
11831   /* if there was something to be popped then do it */
11832   if (popIc)
11833     genIpop (popIc);
11834
11835   /* if the condition is a bit variable */
11836   if (isbit && dup)
11837     genIfxJump (ic, dup);
11838   else if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11839     genIfxJump (ic, SPIL_LOC (cond)->rname);
11840   else if (isbit && !IS_ITEMP (cond))
11841     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11842   else
11843     genIfxJump (ic, "a");
11844
11845   ic->generated = 1;
11846 }
11847
11848 /*-----------------------------------------------------------------*/
11849 /* genAddrOf - generates code for address of                       */
11850 /*-----------------------------------------------------------------*/
11851 static void
11852 genAddrOf (iCode * ic)
11853 {
11854   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11855   int size, offset;
11856
11857   D (emitcode (";", "genAddrOf"));
11858
11859   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11860
11861   /* if the operand is on the stack then we
11862      need to get the stack offset of this
11863      variable */
11864   if (sym->onStack)
11865   {
11866
11867       /* if 10 bit stack */
11868       if (options.stack10bit) {
11869           char buff[10];
11870           int  offset;
11871
11872           tsprintf(buff, sizeof(buff),
11873                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11874           /* if it has an offset then we need to compute it */
11875 /*        emitcode ("subb", "a,#!constbyte", */
11876 /*                  -((sym->stack < 0) ? */
11877 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11878 /*                    ((short) sym->stack)) & 0xff); */
11879 /*        emitcode ("mov","b,a"); */
11880 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11881 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11882 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11883           if (sym->stack) {
11884               emitcode ("mov", "a,_bpx");
11885               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11886                                              ((char) (sym->stack - _G.nRegsSaved)) :
11887                                              ((char) sym->stack )) & 0xff);
11888               emitcode ("mov", "b,a");
11889               emitcode ("mov", "a,_bpx+1");
11890
11891               offset = (((sym->stack < 0) ?
11892                          ((short) (sym->stack - _G.nRegsSaved)) :
11893                          ((short) sym->stack )) >> 8) & 0xff;
11894
11895               emitcode ("addc","a,#!constbyte", offset);
11896
11897               aopPut (IC_RESULT (ic), "b", 0);
11898               aopPut (IC_RESULT (ic), "a", 1);
11899               aopPut (IC_RESULT (ic), buff, 2);
11900           } else {
11901               /* we can just move _bp */
11902               aopPut (IC_RESULT (ic), "_bpx", 0);
11903               aopPut (IC_RESULT (ic), "_bpx+1", 1);
11904               aopPut (IC_RESULT (ic), buff, 2);
11905           }
11906       } else {
11907           /* if it has an offset then we need to compute it */
11908           if (sym->stack)
11909             {
11910               emitcode ("mov", "a,_bp");
11911               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11912               aopPut (IC_RESULT (ic), "a", 0);
11913             }
11914           else
11915             {
11916               /* we can just move _bp */
11917               aopPut (IC_RESULT (ic), "_bp", 0);
11918             }
11919           /* fill the result with zero */
11920           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11921
11922
11923           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11924               fprintf (stderr,
11925                        "*** warning: pointer to stack var truncated.\n");
11926           }
11927
11928           offset = 1;
11929           while (size--)
11930             {
11931               aopPut (IC_RESULT (ic), zero, offset++);
11932             }
11933       }
11934       goto release;
11935   }
11936
11937   /* object not on stack then we need the name */
11938   size = AOP_SIZE (IC_RESULT (ic));
11939   offset = 0;
11940
11941   while (size--)
11942     {
11943       char s[SDCC_NAME_MAX];
11944       if (offset) {
11945           switch (offset) {
11946           case 1:
11947               tsprintf(s, sizeof(s), "#!his",sym->rname);
11948               break;
11949           case 2:
11950               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11951               break;
11952           case 3:
11953               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11954               break;
11955           default: /* should not need this (just in case) */
11956               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11957                        sym->rname,
11958                        offset * 8);
11959           }
11960       }
11961       else
11962       {
11963           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11964       }
11965
11966       aopPut (IC_RESULT (ic), s, offset++);
11967     }
11968
11969 release:
11970   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11971
11972 }
11973
11974 #if 0 // obsolete, and buggy for != xdata
11975 /*-----------------------------------------------------------------*/
11976 /* genArrayInit - generates code for address of                       */
11977 /*-----------------------------------------------------------------*/
11978 static void
11979 genArrayInit (iCode * ic)
11980 {
11981     literalList *iLoop;
11982     int         ix, count;
11983     int         elementSize = 0, eIndex;
11984     unsigned    val, lastVal;
11985     sym_link    *type;
11986     operand     *left=IC_LEFT(ic);
11987
11988     D (emitcode (";", "genArrayInit"));
11989
11990     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11991
11992     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11993     {
11994         // Load immediate value into DPTR.
11995         emitcode("mov", "dptr, %s",
11996              aopGet (IC_LEFT(ic), 0, TRUE, FALSE, NULL));
11997     }
11998     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11999     {
12000 #if 0
12001       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12002               "Unexpected operand to genArrayInit.\n");
12003       exit(1);
12004 #else
12005       // a regression because of SDCCcse.c:1.52
12006       emitcode ("mov", "dpl,%s", aopGet (left, 0, FALSE, FALSE, NULL));
12007       emitcode ("mov", "dph,%s", aopGet (left, 1, FALSE, FALSE, NULL));
12008       if (options.model == MODEL_FLAT24)
12009         emitcode ("mov", "dpx,%s", aopGet (left, 2, FALSE, FALSE, NULL));
12010 #endif
12011     }
12012
12013     type = operandType(IC_LEFT(ic));
12014
12015     if (type && type->next)
12016     {
12017         elementSize = getSize(type->next);
12018     }
12019     else
12020     {
12021         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
12022                                 "can't determine element size in genArrayInit.\n");
12023         exit(1);
12024     }
12025
12026     iLoop = IC_ARRAYILIST(ic);
12027     lastVal = 0xffff;
12028
12029     while (iLoop)
12030     {
12031         bool firstpass = TRUE;
12032
12033         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
12034                  iLoop->count, (int)iLoop->literalValue, elementSize);
12035
12036         ix = iLoop->count;
12037
12038         while (ix)
12039         {
12040             symbol *tlbl = NULL;
12041
12042             count = ix > 256 ? 256 : ix;
12043
12044             if (count > 1)
12045             {
12046                 tlbl = newiTempLabel (NULL);
12047                 if (firstpass || (count & 0xff))
12048                 {
12049                     emitcode("mov", "b, #!constbyte", count & 0xff);
12050                 }
12051
12052                 emitLabel (tlbl);
12053             }
12054
12055             firstpass = FALSE;
12056
12057             for (eIndex = 0; eIndex < elementSize; eIndex++)
12058             {
12059                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12060                 if (val != lastVal)
12061                 {
12062                     emitcode("mov", "a, #!constbyte", val);
12063                     lastVal = val;
12064                 }
12065
12066                 emitcode("movx", "@dptr, a");
12067                 emitcode("inc", "dptr");
12068             }
12069
12070             if (count > 1)
12071             {
12072                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
12073             }
12074
12075             ix -= count;
12076         }
12077
12078         iLoop = iLoop->next;
12079     }
12080
12081     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
12082 }
12083 #endif
12084
12085 /*-----------------------------------------------------------------*/
12086 /* genFarFarAssign - assignment when both are in far space         */
12087 /*-----------------------------------------------------------------*/
12088 static void
12089 genFarFarAssign (operand * result, operand * right, iCode * ic)
12090 {
12091   int size = AOP_SIZE (right);
12092   int offset = 0;
12093   symbol *rSym = NULL;
12094
12095   if (size == 1)
12096   {
12097       /* quick & easy case. */
12098       D (emitcode(";","genFarFarAssign (1 byte case)"));
12099       MOVA (aopGet (right, 0, FALSE, FALSE, NULL));
12100       freeAsmop (right, NULL, ic, FALSE);
12101       /* now assign DPTR to result */
12102       _G.accInUse++;
12103       aopOp(result, ic, FALSE, FALSE);
12104       _G.accInUse--;
12105       aopPut (result, "a", 0);
12106       freeAsmop(result, NULL, ic, FALSE);
12107       return;
12108   }
12109
12110   /* See if we've got an underlying symbol to abuse. */
12111   if (IS_SYMOP(result) && OP_SYMBOL(result))
12112   {
12113       if (IS_TRUE_SYMOP(result))
12114       {
12115           rSym = OP_SYMBOL(result);
12116       }
12117       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
12118       {
12119           rSym = OP_SYMBOL(result)->usl.spillLoc;
12120       }
12121   }
12122
12123   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
12124   {
12125       /* We can use the '390 auto-toggle feature to good effect here. */
12126
12127       D (emitcode(";", "genFarFarAssign (390 auto-toggle fun)"));
12128       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
12129       emitcode ("mov", "dptr,#%s", rSym->rname);
12130       /* DP2 = result, DP1 = right, DP1 is current. */
12131       while (size)
12132       {
12133           emitcode("movx", "a,@dptr");
12134           emitcode("movx", "@dptr,a");
12135           if (--size)
12136           {
12137                emitcode("inc", "dptr");
12138                emitcode("inc", "dptr");
12139           }
12140       }
12141       emitcode("mov", "dps,#0");
12142       freeAsmop (right, NULL, ic, FALSE);
12143 #if 0
12144 some alternative code for processors without auto-toggle
12145 no time to test now, so later well put in...kpb
12146         D (emitcode(";", "genFarFarAssign (dual-dptr fun)"));
12147         emitcode("mov", "dps,#1");      /* Select DPTR2. */
12148         emitcode ("mov", "dptr,#%s", rSym->rname);
12149         /* DP2 = result, DP1 = right, DP1 is current. */
12150         while (size)
12151         {
12152           --size;
12153           emitcode("movx", "a,@dptr");
12154           if (size)
12155             emitcode("inc", "dptr");
12156           emitcode("inc", "dps");
12157           emitcode("movx", "@dptr,a");
12158           if (size)
12159             emitcode("inc", "dptr");
12160           emitcode("inc", "dps");
12161         }
12162         emitcode("mov", "dps,#0");
12163         freeAsmop (right, NULL, ic, FALSE);
12164 #endif
12165   }
12166   else
12167   {
12168       D (emitcode (";", "genFarFarAssign"));
12169       aopOp (result, ic, TRUE, TRUE);
12170
12171       _startLazyDPSEvaluation ();
12172
12173       while (size--)
12174         {
12175           aopPut (result,
12176                   aopGet (right, offset, FALSE, FALSE, NULL), offset);
12177           offset++;
12178         }
12179       _endLazyDPSEvaluation ();
12180       freeAsmop (result, NULL, ic, FALSE);
12181       freeAsmop (right, NULL, ic, FALSE);
12182   }
12183 }
12184
12185 /*-----------------------------------------------------------------*/
12186 /* genAssign - generate code for assignment                        */
12187 /*-----------------------------------------------------------------*/
12188 static void
12189 genAssign (iCode * ic)
12190 {
12191   operand *result, *right;
12192   int size, offset;
12193   unsigned long lit = 0L;
12194
12195   D (emitcode (";", "genAssign"));
12196
12197   result = IC_RESULT (ic);
12198   right = IC_RIGHT (ic);
12199
12200   /* if they are the same */
12201   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12202     return;
12203
12204   aopOp (right, ic, FALSE, FALSE);
12205
12206   emitcode (";", "genAssign: resultIsFar = %s",
12207             isOperandInFarSpace (result) ?
12208             "TRUE" : "FALSE");
12209
12210   /* special case both in far space */
12211   if ((AOP_TYPE (right) == AOP_DPTR ||
12212        AOP_TYPE (right) == AOP_DPTR2) &&
12213   /* IS_TRUE_SYMOP(result)       && */
12214       isOperandInFarSpace (result))
12215     {
12216       genFarFarAssign (result, right, ic);
12217       return;
12218     }
12219
12220   aopOp (result, ic, TRUE, FALSE);
12221
12222   /* if they are the same registers */
12223   if (sameRegs (AOP (right), AOP (result)))
12224     goto release;
12225
12226   /* if the result is a bit */
12227   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
12228     {
12229       /* if the right size is a literal then
12230          we know what the value is */
12231       if (AOP_TYPE (right) == AOP_LIT)
12232         {
12233           if (((int) operandLitValue (right)))
12234             aopPut (result, one, 0);
12235           else
12236             aopPut (result, zero, 0);
12237           goto release;
12238         }
12239
12240       /* the right is also a bit variable */
12241       if (AOP_TYPE (right) == AOP_CRY)
12242         {
12243           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12244           aopPut (result, "c", 0);
12245           goto release;
12246         }
12247
12248       /* we need to or */
12249       toBoolean (right);
12250       aopPut (result, "a", 0);
12251       goto release;
12252     }
12253
12254   /* bit variables done */
12255   /* general case */
12256   size = AOP_SIZE (result);
12257   offset = 0;
12258   if (AOP_TYPE (right) == AOP_LIT)
12259     lit = ulFromVal (AOP (right)->aopu.aop_lit);
12260
12261   if ((size > 1) &&
12262       (AOP_TYPE (result) != AOP_REG) &&
12263       (AOP_TYPE (right) == AOP_LIT) &&
12264       !IS_FLOAT (operandType (right)))
12265     {
12266       _startLazyDPSEvaluation ();
12267       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
12268         {
12269           aopPut (result,
12270                   aopGet (right, offset, FALSE, FALSE, NULL),
12271                   offset);
12272           offset++;
12273           size--;
12274         }
12275       /* And now fill the rest with zeros. */
12276       if (size)
12277         {
12278           emitcode ("clr", "a");
12279         }
12280       while (size--)
12281         {
12282           aopPut (result, "a", offset++);
12283         }
12284       _endLazyDPSEvaluation ();
12285     }
12286   else
12287     {
12288       _startLazyDPSEvaluation ();
12289       while (size--)
12290         {
12291           aopPut (result,
12292                   aopGet (right, offset, FALSE, FALSE, NULL),
12293                   offset);
12294           offset++;
12295         }
12296       _endLazyDPSEvaluation ();
12297     }
12298
12299 release:
12300   freeAsmop (result, NULL, ic, TRUE);
12301   freeAsmop (right, NULL, ic, TRUE);
12302 }
12303
12304 /*-----------------------------------------------------------------*/
12305 /* genJumpTab - generates code for jump table                      */
12306 /*-----------------------------------------------------------------*/
12307 static void
12308 genJumpTab (iCode * ic)
12309 {
12310   symbol *jtab;
12311   char *l;
12312
12313   D (emitcode (";", "genJumpTab"));
12314
12315   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
12316   /* get the condition into accumulator */
12317   l = aopGet (IC_JTCOND (ic), 0, FALSE, FALSE, NULL);
12318   MOVA (l);
12319   /* multiply by four! */
12320   emitcode ("add", "a,acc");
12321   emitcode ("add", "a,acc");
12322   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
12323
12324   jtab = newiTempLabel (NULL);
12325   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
12326   emitcode ("jmp", "@a+dptr");
12327   emitLabel (jtab);
12328   /* now generate the jump labels */
12329   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
12330        jtab = setNextItem (IC_JTLABELS (ic)))
12331     emitcode ("ljmp", "!tlabel", jtab->key + 100);
12332
12333 }
12334
12335 /*-----------------------------------------------------------------*/
12336 /* genCast - gen code for casting                                  */
12337 /*-----------------------------------------------------------------*/
12338 static void
12339 genCast (iCode * ic)
12340 {
12341   operand *result = IC_RESULT (ic);
12342   sym_link *ctype = operandType (IC_LEFT (ic));
12343   sym_link *rtype = operandType (IC_RIGHT (ic));
12344   operand *right = IC_RIGHT (ic);
12345   int size, offset;
12346
12347   D (emitcode (";", "genCast"));
12348
12349   /* if they are equivalent then do nothing */
12350   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
12351     return;
12352
12353   aopOp (right, ic, FALSE, AOP_IS_STR (result));
12354   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
12355
12356   /* if the result is a bit (and not a bitfield) */
12357   if (IS_BIT (OP_SYMBOL (result)->type))
12358     {
12359       /* if the right size is a literal then
12360          we know what the value is */
12361       if (AOP_TYPE (right) == AOP_LIT)
12362         {
12363           if (((int) operandLitValue (right)))
12364             aopPut (result, one, 0);
12365           else
12366             aopPut (result, zero, 0);
12367
12368           goto release;
12369         }
12370
12371       /* the right is also a bit variable */
12372       if (AOP_TYPE (right) == AOP_CRY)
12373         {
12374           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
12375           aopPut (result, "c", 0);
12376           goto release;
12377         }
12378
12379       /* we need to or */
12380       toBoolean (right);
12381       aopPut (result, "a", 0);
12382       goto release;
12383     }
12384
12385   /* if they are the same size : or less */
12386   if (AOP_SIZE (result) <= AOP_SIZE (right))
12387     {
12388
12389       /* if they are in the same place */
12390       if (sameRegs (AOP (right), AOP (result)))
12391         goto release;
12392
12393       /* if they in different places then copy */
12394       size = AOP_SIZE (result);
12395       offset = 0;
12396       _startLazyDPSEvaluation ();
12397       while (size--)
12398         {
12399           aopPut (result,
12400                   aopGet (right, offset, FALSE, FALSE, NULL),
12401                   offset);
12402           offset++;
12403         }
12404       _endLazyDPSEvaluation ();
12405       goto release;
12406     }
12407
12408   /* if the result is of type pointer */
12409   if (IS_PTR (ctype))
12410     {
12411
12412       int p_type;
12413       sym_link *type = operandType (right);
12414
12415       /* pointer to generic pointer */
12416       if (IS_GENPTR (ctype))
12417         {
12418           if (IS_PTR (type))
12419             {
12420               p_type = DCL_TYPE (type);
12421             }
12422           else
12423             {
12424 #if OLD_CAST_BEHAVIOR
12425               /* KV: we are converting a non-pointer type to
12426                * a generic pointer. This (ifdef'd out) code
12427                * says that the resulting generic pointer
12428                * should have the same class as the storage
12429                * location of the non-pointer variable.
12430                *
12431                * For example, converting an int (which happens
12432                * to be stored in DATA space) to a pointer results
12433                * in a DATA generic pointer; if the original int
12434                * in XDATA space, so will be the resulting pointer.
12435                *
12436                * I don't like that behavior, and thus this change:
12437                * all such conversions will be forced to XDATA and
12438                * throw a warning. If you want some non-XDATA
12439                * type, or you want to suppress the warning, you
12440                * must go through an intermediate cast, like so:
12441                *
12442                * char _generic *gp = (char _xdata *)(intVar);
12443                */
12444               sym_link *etype = getSpec (type);
12445
12446               /* we have to go by the storage class */
12447               if (SPEC_OCLS (etype) != generic)
12448                 {
12449                   p_type = PTR_TYPE (SPEC_OCLS (etype));
12450                 }
12451               else
12452 #endif
12453                 {
12454                   /* Converting unknown class (i.e. register variable)
12455                    * to generic pointer. This is not good, but
12456                    * we'll make a guess (and throw a warning).
12457                    */
12458                   p_type = FPOINTER;
12459                   werror (W_INT_TO_GEN_PTR_CAST);
12460                 }
12461             }
12462
12463           /* the first two bytes are known */
12464           size = GPTRSIZE - 1;
12465           offset = 0;
12466           _startLazyDPSEvaluation ();
12467           while (size--)
12468             {
12469               aopPut (result,
12470                       aopGet (right, offset, FALSE, FALSE, NULL),
12471                       offset);
12472               offset++;
12473             }
12474           _endLazyDPSEvaluation ();
12475
12476           /* the last byte depending on type */
12477             {
12478                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
12479                 char gpValStr[10];
12480
12481                 if (gpVal == -1)
12482                 {
12483                     // pointerTypeToGPByte will have bitched.
12484                     exit(1);
12485                 }
12486
12487                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%x", gpVal);
12488                 aopPut (result, gpValStr, GPTRSIZE - 1);
12489             }
12490           goto release;
12491         }
12492
12493       /* just copy the pointers */
12494       size = AOP_SIZE (result);
12495       offset = 0;
12496       _startLazyDPSEvaluation ();
12497       while (size--)
12498         {
12499           aopPut (result,
12500                   aopGet (right, offset, FALSE, FALSE, NULL),
12501                   offset);
12502           offset++;
12503         }
12504       _endLazyDPSEvaluation ();
12505       goto release;
12506     }
12507
12508   /* so we now know that the size of destination is greater
12509      than the size of the source */
12510   /* we move to result for the size of source */
12511   size = AOP_SIZE (right);
12512   offset = 0;
12513   _startLazyDPSEvaluation ();
12514   while (size--)
12515     {
12516       aopPut (result,
12517               aopGet (right, offset, FALSE, FALSE, NULL),
12518               offset);
12519       offset++;
12520     }
12521   _endLazyDPSEvaluation ();
12522
12523   /* now depending on the sign of the source && destination */
12524   size = AOP_SIZE (result) - AOP_SIZE (right);
12525   /* if unsigned or not an integral type */
12526   /* also, if the source is a bit, we don't need to sign extend, because
12527    * it can't possibly have set the sign bit.
12528    */
12529   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
12530     {
12531       while (size--)
12532         {
12533           aopPut (result, zero, offset++);
12534         }
12535     }
12536   else
12537     {
12538       /* we need to extend the sign :{ */
12539       MOVA (aopGet (right, AOP_SIZE (right) - 1,
12540                         FALSE, FALSE, NULL));
12541       emitcode ("rlc", "a");
12542       emitcode ("subb", "a,acc");
12543       while (size--)
12544         aopPut (result, "a", offset++);
12545     }
12546
12547   /* we are done hurray !!!! */
12548
12549 release:
12550   freeAsmop (right, NULL, ic, TRUE);
12551   freeAsmop (result, NULL, ic, TRUE);
12552
12553 }
12554
12555 /*-----------------------------------------------------------------*/
12556 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
12557 /*-----------------------------------------------------------------*/
12558 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
12559 {
12560     operand *from , *to , *count;
12561     symbol *lbl;
12562     bitVect *rsave;
12563     int i;
12564
12565     /* we know it has to be 3 parameters */
12566     assert (nparms == 3);
12567
12568     rsave = newBitVect(16);
12569     /* save DPTR if it needs to be saved */
12570     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12571             if (bitVectBitValue(ic->rMask,i))
12572                     rsave = bitVectSetBit(rsave,i);
12573     }
12574     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12575                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12576     savermask(rsave);
12577
12578     to = parms[0];
12579     from = parms[1];
12580     count = parms[2];
12581
12582     aopOp (from, ic->next, FALSE, FALSE);
12583
12584     /* get from into DPTR1 */
12585     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12586     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12587     if (options.model == MODEL_FLAT24) {
12588         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12589     }
12590
12591     freeAsmop (from, NULL, ic, FALSE);
12592     aopOp (to, ic, FALSE, FALSE);
12593     /* get "to" into DPTR */
12594     /* if the operand is already in dptr
12595        then we do nothing else we move the value to dptr */
12596     if (AOP_TYPE (to) != AOP_STR) {
12597         /* if already in DPTR then we need to push */
12598         if (AOP_TYPE(to) == AOP_DPTR) {
12599             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12600             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12601             if (options.model == MODEL_FLAT24)
12602                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12603             emitcode ("pop", "dph");
12604             emitcode ("pop", "dpl");
12605         } else {
12606             _startLazyDPSEvaluation ();
12607             /* if this is remateriazable */
12608             if (AOP_TYPE (to) == AOP_IMMD) {
12609                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12610             } else {                    /* we need to get it byte by byte */
12611                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12612                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12613                 if (options.model == MODEL_FLAT24) {
12614                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12615                 }
12616             }
12617             _endLazyDPSEvaluation ();
12618         }
12619     }
12620     freeAsmop (to, NULL, ic, FALSE);
12621     _G.dptrInUse = _G.dptr1InUse = 1;
12622     aopOp (count, ic->next->next, FALSE,FALSE);
12623     lbl =newiTempLabel(NULL);
12624
12625     /* now for the actual copy */
12626     if (AOP_TYPE(count) == AOP_LIT &&
12627         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12628         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12629         if (fromc) {
12630             emitcode ("lcall","__bi_memcpyc2x_s");
12631         } else {
12632             emitcode ("lcall","__bi_memcpyx2x_s");
12633         }
12634         freeAsmop (count, NULL, ic, FALSE);
12635     } else {
12636         symbol *lbl1 = newiTempLabel(NULL);
12637
12638         emitcode (";"," Auto increment but no djnz");
12639         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12640         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12641         freeAsmop (count, NULL, ic, FALSE);
12642         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12643         emitLabel (lbl);
12644         if (fromc) {
12645             emitcode ("clr","a");
12646             emitcode ("movc", "a,@a+dptr");
12647         } else
12648             emitcode ("movx", "a,@dptr");
12649         emitcode ("movx", "@dptr,a");
12650         emitcode ("inc", "dptr");
12651         emitcode ("inc", "dptr");
12652         emitcode ("mov","a,b");
12653         emitcode ("orl","a,_ap");
12654         emitcode ("jz","!tlabel",lbl1->key+100);
12655         emitcode ("mov","a,_ap");
12656         emitcode ("add","a,#!constbyte",0xFF);
12657         emitcode ("mov","_ap,a");
12658         emitcode ("mov","a,b");
12659         emitcode ("addc","a,#!constbyte",0xFF);
12660         emitcode ("mov","b,a");
12661         emitcode ("sjmp","!tlabel",lbl->key+100);
12662         emitLabel (lbl1);
12663     }
12664     emitcode ("mov", "dps,#0");
12665     _G.dptrInUse = _G.dptr1InUse = 0;
12666     unsavermask(rsave);
12667
12668 }
12669
12670 /*-----------------------------------------------------------------*/
12671 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12672 /*-----------------------------------------------------------------*/
12673 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12674 {
12675     operand *from , *to , *count;
12676     symbol *lbl,*lbl2;
12677     bitVect *rsave;
12678     int i;
12679
12680     /* we know it has to be 3 parameters */
12681     assert (nparms == 3);
12682
12683     rsave = newBitVect(16);
12684     /* save DPTR if it needs to be saved */
12685     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12686             if (bitVectBitValue(ic->rMask,i))
12687                     rsave = bitVectSetBit(rsave,i);
12688     }
12689     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12690                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12691     savermask(rsave);
12692
12693     to = parms[0];
12694     from = parms[1];
12695     count = parms[2];
12696
12697     aopOp (from, ic->next, FALSE, FALSE);
12698
12699     /* get from into DPTR1 */
12700     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12701     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12702     if (options.model == MODEL_FLAT24) {
12703         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12704     }
12705
12706     freeAsmop (from, NULL, ic, FALSE);
12707     aopOp (to, ic, FALSE, FALSE);
12708     /* get "to" into DPTR */
12709     /* if the operand is already in dptr
12710        then we do nothing else we move the value to dptr */
12711     if (AOP_TYPE (to) != AOP_STR) {
12712         /* if already in DPTR then we need to push */
12713         if (AOP_TYPE(to) == AOP_DPTR) {
12714             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12715             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12716             if (options.model == MODEL_FLAT24)
12717                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12718             emitcode ("pop", "dph");
12719             emitcode ("pop", "dpl");
12720         } else {
12721             _startLazyDPSEvaluation ();
12722             /* if this is remateriazable */
12723             if (AOP_TYPE (to) == AOP_IMMD) {
12724                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12725             } else {                    /* we need to get it byte by byte */
12726                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12727                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12728                 if (options.model == MODEL_FLAT24) {
12729                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12730                 }
12731             }
12732             _endLazyDPSEvaluation ();
12733         }
12734     }
12735     freeAsmop (to, NULL, ic, FALSE);
12736     _G.dptrInUse = _G.dptr1InUse = 1;
12737     aopOp (count, ic->next->next, FALSE,FALSE);
12738     lbl =newiTempLabel(NULL);
12739     lbl2 =newiTempLabel(NULL);
12740
12741     /* now for the actual compare */
12742     if (AOP_TYPE(count) == AOP_LIT &&
12743         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12744         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12745         if (fromc)
12746             emitcode("lcall","__bi_memcmpc2x_s");
12747         else
12748             emitcode("lcall","__bi_memcmpx2x_s");
12749         freeAsmop (count, NULL, ic, FALSE);
12750         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12751         aopPut(IC_RESULT(ic),"a",0);
12752         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12753     } else {
12754         symbol *lbl1 = newiTempLabel(NULL);
12755
12756         emitcode("push","ar0");
12757         emitcode (";"," Auto increment but no djnz");
12758         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12759         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12760         freeAsmop (count, NULL, ic, FALSE);
12761         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12762         emitLabel (lbl);
12763         if (fromc) {
12764             emitcode ("clr","a");
12765             emitcode ("movc", "a,@a+dptr");
12766         } else
12767             emitcode ("movx", "a,@dptr");
12768         emitcode ("mov","r0,a");
12769         emitcode ("movx", "a,@dptr");
12770         emitcode ("clr","c");
12771         emitcode ("subb","a,r0");
12772         emitcode ("jnz","!tlabel",lbl2->key+100);
12773         emitcode ("inc", "dptr");
12774         emitcode ("inc", "dptr");
12775         emitcode ("mov","a,b");
12776         emitcode ("orl","a,_ap");
12777         emitcode ("jz","!tlabel",lbl1->key+100);
12778         emitcode ("mov","a,_ap");
12779         emitcode ("add","a,#!constbyte",0xFF);
12780         emitcode ("mov","_ap,a");
12781         emitcode ("mov","a,b");
12782         emitcode ("addc","a,#!constbyte",0xFF);
12783         emitcode ("mov","b,a");
12784         emitcode ("sjmp","!tlabel",lbl->key+100);
12785         emitLabel (lbl1);
12786         emitcode ("clr","a");
12787         emitLabel (lbl2);
12788         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12789         aopPut(IC_RESULT(ic),"a",0);
12790         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12791         emitcode("pop","ar0");
12792         emitcode ("mov", "dps,#0");
12793     }
12794     _G.dptrInUse = _G.dptr1InUse = 0;
12795     unsavermask(rsave);
12796
12797 }
12798
12799 /*-----------------------------------------------------------------*/
12800 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12801 /* port, first parameter output area second parameter pointer to   */
12802 /* port third parameter count                                      */
12803 /*-----------------------------------------------------------------*/
12804 static void genInp( iCode *ic, int nparms, operand **parms)
12805 {
12806     operand *from , *to , *count;
12807     symbol *lbl;
12808     bitVect *rsave;
12809     int i;
12810
12811     /* we know it has to be 3 parameters */
12812     assert (nparms == 3);
12813
12814     rsave = newBitVect(16);
12815     /* save DPTR if it needs to be saved */
12816     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12817             if (bitVectBitValue(ic->rMask,i))
12818                     rsave = bitVectSetBit(rsave,i);
12819     }
12820     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12821                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12822     savermask(rsave);
12823
12824     to = parms[0];
12825     from = parms[1];
12826     count = parms[2];
12827
12828     aopOp (from, ic->next, FALSE, FALSE);
12829
12830     /* get from into DPTR1 */
12831     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12832     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12833     if (options.model == MODEL_FLAT24) {
12834         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12835     }
12836
12837     freeAsmop (from, NULL, ic, FALSE);
12838     aopOp (to, ic, FALSE, FALSE);
12839     /* get "to" into DPTR */
12840     /* if the operand is already in dptr
12841        then we do nothing else we move the value to dptr */
12842     if (AOP_TYPE (to) != AOP_STR) {
12843         /* if already in DPTR then we need to push */
12844         if (AOP_TYPE(to) == AOP_DPTR) {
12845             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12846             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12847             if (options.model == MODEL_FLAT24)
12848                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12849             emitcode ("pop", "dph");
12850             emitcode ("pop", "dpl");
12851         } else {
12852             _startLazyDPSEvaluation ();
12853             /* if this is remateriazable */
12854             if (AOP_TYPE (to) == AOP_IMMD) {
12855                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12856             } else {                    /* we need to get it byte by byte */
12857                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12858                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12859                 if (options.model == MODEL_FLAT24) {
12860                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12861                 }
12862             }
12863             _endLazyDPSEvaluation ();
12864         }
12865     }
12866     freeAsmop (to, NULL, ic, FALSE);
12867
12868     _G.dptrInUse = _G.dptr1InUse = 1;
12869     aopOp (count, ic->next->next, FALSE,FALSE);
12870     lbl =newiTempLabel(NULL);
12871
12872     /* now for the actual copy */
12873     if (AOP_TYPE(count) == AOP_LIT &&
12874         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12875         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12876         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12877         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12878         freeAsmop (count, NULL, ic, FALSE);
12879         emitLabel (lbl);
12880         emitcode ("movx", "a,@dptr");   /* read data from port */
12881         emitcode ("dec","dps");         /* switch to DPTR */
12882         emitcode ("movx", "@dptr,a");   /* save into location */
12883         emitcode ("inc", "dptr");       /* point to next area */
12884         emitcode ("inc","dps");         /* switch to DPTR2 */
12885         emitcode ("djnz","b,!tlabel",lbl->key+100);
12886     } else {
12887         symbol *lbl1 = newiTempLabel(NULL);
12888
12889         emitcode (";"," Auto increment but no djnz");
12890         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
12891         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
12892         freeAsmop (count, NULL, ic, FALSE);
12893         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12894         emitLabel (lbl);
12895         emitcode ("movx", "a,@dptr");
12896         emitcode ("dec","dps");         /* switch to DPTR */
12897         emitcode ("movx", "@dptr,a");
12898         emitcode ("inc", "dptr");
12899         emitcode ("inc","dps");         /* switch to DPTR2 */
12900 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12901 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12902         emitcode ("mov","a,b");
12903         emitcode ("orl","a,_ap");
12904         emitcode ("jz","!tlabel",lbl1->key+100);
12905         emitcode ("mov","a,_ap");
12906         emitcode ("add","a,#!constbyte",0xFF);
12907         emitcode ("mov","_ap,a");
12908         emitcode ("mov","a,b");
12909         emitcode ("addc","a,#!constbyte",0xFF);
12910         emitcode ("mov","b,a");
12911         emitcode ("sjmp","!tlabel",lbl->key+100);
12912         emitLabel (lbl1);
12913     }
12914     emitcode ("mov", "dps,#0");
12915     _G.dptrInUse = _G.dptr1InUse = 0;
12916     unsavermask(rsave);
12917
12918 }
12919
12920 /*-----------------------------------------------------------------*/
12921 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12922 /* port, first parameter output area second parameter pointer to   */
12923 /* port third parameter count                                      */
12924 /*-----------------------------------------------------------------*/
12925 static void genOutp( iCode *ic, int nparms, operand **parms)
12926 {
12927     operand *from , *to , *count;
12928     symbol *lbl;
12929     bitVect *rsave;
12930     int i;
12931
12932     /* we know it has to be 3 parameters */
12933     assert (nparms == 3);
12934
12935     rsave = newBitVect(16);
12936     /* save DPTR if it needs to be saved */
12937     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12938             if (bitVectBitValue(ic->rMask,i))
12939                     rsave = bitVectSetBit(rsave,i);
12940     }
12941     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12942                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12943     savermask(rsave);
12944
12945     to = parms[0];
12946     from = parms[1];
12947     count = parms[2];
12948
12949     aopOp (from, ic->next, FALSE, FALSE);
12950
12951     /* get from into DPTR1 */
12952     emitcode ("mov", "dpl1,%s", aopGet (from, 0, FALSE, FALSE, NULL));
12953     emitcode ("mov", "dph1,%s", aopGet (from, 1, FALSE, FALSE, NULL));
12954     if (options.model == MODEL_FLAT24) {
12955         emitcode ("mov", "dpx1,%s", aopGet (from, 2, FALSE, FALSE, NULL));
12956     }
12957
12958     freeAsmop (from, NULL, ic, FALSE);
12959     aopOp (to, ic, FALSE, FALSE);
12960     /* get "to" into DPTR */
12961     /* if the operand is already in dptr
12962        then we do nothing else we move the value to dptr */
12963     if (AOP_TYPE (to) != AOP_STR) {
12964         /* if already in DPTR then we need to push */
12965         if (AOP_TYPE(to) == AOP_DPTR) {
12966             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
12967             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
12968             if (options.model == MODEL_FLAT24)
12969                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12970             emitcode ("pop", "dph");
12971             emitcode ("pop", "dpl");
12972         } else {
12973             _startLazyDPSEvaluation ();
12974             /* if this is remateriazable */
12975             if (AOP_TYPE (to) == AOP_IMMD) {
12976                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
12977             } else {                    /* we need to get it byte by byte */
12978                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
12979                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
12980                 if (options.model == MODEL_FLAT24) {
12981                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
12982                 }
12983             }
12984             _endLazyDPSEvaluation ();
12985         }
12986     }
12987     freeAsmop (to, NULL, ic, FALSE);
12988
12989     _G.dptrInUse = _G.dptr1InUse = 1;
12990     aopOp (count, ic->next->next, FALSE,FALSE);
12991     lbl =newiTempLabel(NULL);
12992
12993     /* now for the actual copy */
12994     if (AOP_TYPE(count) == AOP_LIT &&
12995         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12996         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12997         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12998         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
12999         emitLabel (lbl);
13000         emitcode ("movx", "a,@dptr");   /* read data from port */
13001         emitcode ("inc","dps");         /* switch to DPTR2 */
13002         emitcode ("movx", "@dptr,a");   /* save into location */
13003         emitcode ("inc", "dptr");       /* point to next area */
13004         emitcode ("dec","dps");         /* switch to DPTR */
13005         emitcode ("djnz","b,!tlabel",lbl->key+100);
13006         freeAsmop (count, NULL, ic, FALSE);
13007     } else {
13008         symbol *lbl1 = newiTempLabel(NULL);
13009
13010         emitcode (";"," Auto increment but no djnz");
13011         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13012         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13013         freeAsmop (count, NULL, ic, FALSE);
13014         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
13015         emitLabel (lbl);
13016         emitcode ("movx", "a,@dptr");
13017         emitcode ("inc", "dptr");
13018         emitcode ("inc","dps");         /* switch to DPTR2 */
13019         emitcode ("movx", "@dptr,a");
13020         emitcode ("dec","dps");         /* switch to DPTR */
13021         emitcode ("mov","a,b");
13022         emitcode ("orl","a,_ap");
13023         emitcode ("jz","!tlabel",lbl1->key+100);
13024         emitcode ("mov","a,_ap");
13025         emitcode ("add","a,#!constbyte",0xFF);
13026         emitcode ("mov","_ap,a");
13027         emitcode ("mov","a,b");
13028         emitcode ("addc","a,#!constbyte",0xFF);
13029         emitcode ("mov","b,a");
13030         emitcode ("sjmp","!tlabel",lbl->key+100);
13031         emitLabel (lbl1);
13032     }
13033     emitcode ("mov", "dps,#0");
13034     _G.dptrInUse = _G.dptr1InUse = 0;
13035     unsavermask(rsave);
13036
13037 }
13038
13039 /*-----------------------------------------------------------------*/
13040 /* genSwapW - swap lower & high order bytes                        */
13041 /*-----------------------------------------------------------------*/
13042 static void genSwapW(iCode *ic, int nparms, operand **parms)
13043 {
13044     operand *dest;
13045     operand *src;
13046     assert (nparms==1);
13047
13048     src = parms[0];
13049     dest=IC_RESULT(ic);
13050
13051     assert(getSize(operandType(src))==2);
13052
13053     aopOp (src, ic, FALSE, FALSE);
13054     emitcode ("mov","a,%s",aopGet(src,0,FALSE,FALSE,NULL));
13055     _G.accInUse++;
13056     MOVB(aopGet(src,1,FALSE,FALSE,"b"));
13057     _G.accInUse--;
13058     freeAsmop (src, NULL, ic, FALSE);
13059
13060     aopOp (dest,ic, FALSE, FALSE);
13061     aopPut(dest,"b",0);
13062     aopPut(dest,"a",1);
13063     freeAsmop (dest, NULL, ic, FALSE);
13064 }
13065
13066 /*-----------------------------------------------------------------*/
13067 /* genMemsetX - gencode for memSetX data                           */
13068 /*-----------------------------------------------------------------*/
13069 static void genMemsetX(iCode *ic, int nparms, operand **parms)
13070 {
13071     operand *to , *val , *count;
13072     symbol *lbl;
13073     char *l;
13074     int i;
13075     bitVect *rsave;
13076
13077     /* we know it has to be 3 parameters */
13078     assert (nparms == 3);
13079
13080     to = parms[0];
13081     val = parms[1];
13082     count = parms[2];
13083
13084     /* save DPTR if it needs to be saved */
13085     rsave = newBitVect(16);
13086     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
13087             if (bitVectBitValue(ic->rMask,i))
13088                     rsave = bitVectSetBit(rsave,i);
13089     }
13090     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
13091                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
13092     savermask(rsave);
13093
13094     aopOp (to, ic, FALSE, FALSE);
13095     /* get "to" into DPTR */
13096     /* if the operand is already in dptr
13097        then we do nothing else we move the value to dptr */
13098     if (AOP_TYPE (to) != AOP_STR) {
13099         /* if already in DPTR then we need to push */
13100         if (AOP_TYPE(to) == AOP_DPTR) {
13101             emitcode ("push", "%s", aopGet (to, 0, FALSE, TRUE, NULL));
13102             emitcode ("push", "%s", aopGet (to, 1, FALSE, TRUE, NULL));
13103             if (options.model == MODEL_FLAT24)
13104                 emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13105             emitcode ("pop", "dph");
13106             emitcode ("pop", "dpl");
13107         } else {
13108             _startLazyDPSEvaluation ();
13109             /* if this is remateriazable */
13110             if (AOP_TYPE (to) == AOP_IMMD) {
13111                 emitcode ("mov", "dptr,%s", aopGet (to, 0, TRUE, FALSE, NULL));
13112             } else {                    /* we need to get it byte by byte */
13113                 emitcode ("mov", "dpl,%s", aopGet (to, 0, FALSE, FALSE, NULL));
13114                 emitcode ("mov", "dph,%s", aopGet (to, 1, FALSE, FALSE, NULL));
13115                 if (options.model == MODEL_FLAT24) {
13116                     emitcode ("mov", "dpx,%s", aopGet (to, 2, FALSE, FALSE, NULL));
13117                 }
13118             }
13119             _endLazyDPSEvaluation ();
13120         }
13121     }
13122     freeAsmop (to, NULL, ic, FALSE);
13123
13124     aopOp (val, ic->next->next, FALSE,FALSE);
13125     aopOp (count, ic->next->next, FALSE,FALSE);
13126     lbl =newiTempLabel(NULL);
13127     /* now for the actual copy */
13128     if (AOP_TYPE(count) == AOP_LIT &&
13129         (int) ulFromVal (AOP(count)->aopu.aop_lit) <= 256) {
13130         l = aopGet(val, 0, FALSE, FALSE, NULL);
13131         emitcode ("mov", "b,%s",aopGet(count,0,FALSE,FALSE,NULL));
13132         MOVA(l);
13133         emitLabel (lbl);
13134         emitcode ("movx", "@dptr,a");
13135         emitcode ("inc", "dptr");
13136         emitcode ("djnz","b,!tlabel",lbl->key+100);
13137     } else {
13138         symbol *lbl1 = newiTempLabel(NULL);
13139
13140         emitcode ("mov","_ap,%s",aopGet (count, 0, FALSE, TRUE, NULL));
13141         emitcode ("mov","b,%s",aopGet (count, 1, FALSE, TRUE, NULL));
13142         emitLabel (lbl);
13143         MOVA (aopGet(val, 0, FALSE, FALSE, NULL));
13144         emitcode ("movx", "@dptr,a");
13145         emitcode ("inc", "dptr");
13146         emitcode ("mov","a,b");
13147         emitcode ("orl","a,_ap");
13148         emitcode ("jz","!tlabel",lbl1->key+100);
13149         emitcode ("mov","a,_ap");
13150         emitcode ("add","a,#!constbyte",0xFF);
13151         emitcode ("mov","_ap,a");
13152         emitcode ("mov","a,b");
13153         emitcode ("addc","a,#!constbyte",0xFF);
13154         emitcode ("mov","b,a");
13155         emitcode ("sjmp","!tlabel",lbl->key+100);
13156         emitLabel (lbl1);
13157     }
13158     freeAsmop (count, NULL, ic, FALSE);
13159     unsavermask(rsave);
13160 }
13161
13162 /*-----------------------------------------------------------------*/
13163 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
13164 /*-----------------------------------------------------------------*/
13165 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
13166 {
13167         bitVect *rsave ;
13168         operand *pnum, *result;
13169         int i;
13170
13171         assert (nparms==1);
13172         /* save registers that need to be saved */
13173         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13174                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13175
13176         pnum = parms[0];
13177         aopOp (pnum, ic, FALSE, FALSE);
13178         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13179         freeAsmop (pnum, NULL, ic, FALSE);
13180         emitcode ("lcall","NatLib_LoadPrimitive");
13181         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13182         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
13183             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
13184                 for (i = (size-1) ; i >= 0 ; i-- ) {
13185                         emitcode ("push","a%s",javaRet[i]);
13186                 }
13187                 for (i=0; i < size ; i++ ) {
13188                         emitcode ("pop","a%s",
13189                                   aopGet(result,i,FALSE,FALSE,DP2_RESULT_REG));
13190                 }
13191         } else {
13192                 for (i = 0 ; i < size ; i++ ) {
13193                         aopPut(result,javaRet[i],i);
13194                 }
13195         }
13196         freeAsmop (result, NULL, ic, FALSE);
13197         unsavermask(rsave);
13198 }
13199
13200 /*-----------------------------------------------------------------*/
13201 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
13202 /*-----------------------------------------------------------------*/
13203 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
13204 {
13205         bitVect *rsave ;
13206         operand *pnum, *result;
13207         int size = 3;
13208         int i;
13209
13210         assert (nparms==1);
13211         /* save registers that need to be saved */
13212         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13213                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13214
13215         pnum = parms[0];
13216         aopOp (pnum, ic, FALSE, FALSE);
13217         emitcode ("mov","a,%s",aopGet(pnum,0,FALSE,FALSE,DP2_RESULT_REG));
13218         freeAsmop (pnum, NULL, ic, FALSE);
13219         emitcode ("lcall","NatLib_LoadPointer");
13220         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
13221         if (AOP_TYPE(result)!=AOP_STR) {
13222                 for (i = 0 ; i < size ; i++ ) {
13223                         aopPut(result,fReturn[i],i);
13224                 }
13225         }
13226         freeAsmop (result, NULL, ic, FALSE);
13227         unsavermask(rsave);
13228 }
13229
13230 /*-----------------------------------------------------------------*/
13231 /* genNatLibInstallStateBlock -                                    */
13232 /*-----------------------------------------------------------------*/
13233 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
13234                                        operand **parms, const char *name)
13235 {
13236         bitVect *rsave ;
13237         operand *psb, *handle;
13238         assert (nparms==2);
13239
13240         /* save registers that need to be saved */
13241         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13242                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13243         psb = parms[0];
13244         handle = parms[1];
13245
13246         /* put pointer to state block into DPTR1 */
13247         aopOp (psb, ic, FALSE, FALSE);
13248         if (AOP_TYPE (psb) == AOP_IMMD) {
13249                 emitcode ("mov","dps,#1");
13250                 emitcode ("mov", "dptr,%s",
13251                           aopGet (psb, 0, TRUE, FALSE, DP2_RESULT_REG));
13252                 emitcode ("mov","dps,#0");
13253         } else {
13254                 emitcode ("mov","dpl1,%s",aopGet(psb,0,FALSE,FALSE,DP2_RESULT_REG));
13255                 emitcode ("mov","dph1,%s",aopGet(psb,1,FALSE,FALSE,DP2_RESULT_REG));
13256                 emitcode ("mov","dpx1,%s",aopGet(psb,2,FALSE,FALSE,DP2_RESULT_REG));
13257         }
13258         freeAsmop (psb, NULL, ic, FALSE);
13259
13260         /* put libraryID into DPTR */
13261         emitcode ("mov","dptr,#LibraryID");
13262
13263         /* put handle into r3:r2 */
13264         aopOp (handle, ic, FALSE, FALSE);
13265         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13266                 emitcode ("push","%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13267                 emitcode ("push","%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13268                 emitcode ("pop","ar3");
13269                 emitcode ("pop","ar2");
13270         } else {
13271                 emitcode ("mov","r2,%s",aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13272                 emitcode ("mov","r3,%s",aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13273         }
13274         freeAsmop (psb, NULL, ic, FALSE);
13275
13276         /* make the call */
13277         emitcode ("lcall","NatLib_Install%sStateBlock",name);
13278
13279         /* put return value into place*/
13280         _G.accInUse++;
13281         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
13282         _G.accInUse--;
13283         aopPut(IC_RESULT(ic),"a",0);
13284         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13285         unsavermask(rsave);
13286 }
13287
13288 /*-----------------------------------------------------------------*/
13289 /* genNatLibRemoveStateBlock -                                     */
13290 /*-----------------------------------------------------------------*/
13291 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
13292 {
13293         bitVect *rsave ;
13294
13295         assert(nparms==0);
13296
13297         /* save registers that need to be saved */
13298         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13299                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13300
13301         /* put libraryID into DPTR */
13302         emitcode ("mov","dptr,#LibraryID");
13303         /* make the call */
13304         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13305         unsavermask(rsave);
13306 }
13307
13308 /*-----------------------------------------------------------------*/
13309 /* genNatLibGetStateBlock -                                        */
13310 /*-----------------------------------------------------------------*/
13311 static void genNatLibGetStateBlock(iCode *ic,int nparms,
13312                                    operand **parms,const char *name)
13313 {
13314         bitVect *rsave ;
13315         symbol *lbl = newiTempLabel(NULL);
13316
13317         assert(nparms==0);
13318         /* save registers that need to be saved */
13319         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13320                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13321
13322         /* put libraryID into DPTR */
13323         emitcode ("mov","dptr,#LibraryID");
13324         /* make the call */
13325         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
13326         emitcode ("jnz","!tlabel",lbl->key+100);
13327
13328         /* put return value into place */
13329         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13330         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13331                 emitcode ("push","ar3");
13332                 emitcode ("push","ar2");
13333                 emitcode ("pop","%s",
13334                           aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13335                 emitcode ("pop","%s",
13336                           aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13337         } else {
13338                 aopPut(IC_RESULT(ic),"r2",0);
13339                 aopPut(IC_RESULT(ic),"r3",1);
13340         }
13341         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13342         emitLabel (lbl);
13343         unsavermask(rsave);
13344 }
13345
13346 /*-----------------------------------------------------------------*/
13347 /* genMMMalloc -                                                   */
13348 /*-----------------------------------------------------------------*/
13349 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
13350                          int size, const char *name)
13351 {
13352         bitVect *rsave ;
13353         operand *bsize;
13354         symbol *rsym;
13355         symbol *lbl = newiTempLabel(NULL);
13356
13357         assert (nparms == 1);
13358         /* save registers that need to be saved */
13359         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13360                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13361
13362         bsize=parms[0];
13363         aopOp (bsize,ic,FALSE,FALSE);
13364
13365         /* put the size in R4-R2 */
13366         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
13367                 emitcode("push","%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13368                 emitcode("push","%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13369                 if (size==3) {
13370                         emitcode("push","%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13371                         emitcode("pop","ar4");
13372                 }
13373                 emitcode("pop","ar3");
13374                 emitcode("pop","ar2");
13375         } else {
13376                 emitcode ("mov","r2,%s",aopGet(bsize,0,FALSE,TRUE,DP2_RESULT_REG));
13377                 emitcode ("mov","r3,%s",aopGet(bsize,1,FALSE,TRUE,DP2_RESULT_REG));
13378                 if (size==3) {
13379                         emitcode("mov","r4,%s",aopGet(bsize,2,FALSE,TRUE,DP2_RESULT_REG));
13380                 }
13381         }
13382         freeAsmop (bsize, NULL, ic, FALSE);
13383
13384         /* make the call */
13385         emitcode ("lcall","MM_%s",name);
13386         emitcode ("jz","!tlabel",lbl->key+100);
13387         emitcode ("mov","r2,#!constbyte",0xff);
13388         emitcode ("mov","r3,#!constbyte",0xff);
13389         emitLabel (lbl);
13390         /* we don't care about the pointer : we just save the handle */
13391         rsym = OP_SYMBOL(IC_RESULT(ic));
13392         if (rsym->liveFrom != rsym->liveTo) {
13393                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
13394                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
13395                         emitcode ("push","ar3");
13396                         emitcode ("push","ar2");
13397                         emitcode ("pop","%s",
13398                                   aopGet(IC_RESULT(ic),0,FALSE,TRUE,DP2_RESULT_REG));
13399                         emitcode ("pop","%s",
13400                                   aopGet(IC_RESULT(ic),1,FALSE,TRUE,DP2_RESULT_REG));
13401                 } else {
13402                         aopPut(IC_RESULT(ic),"r2",0);
13403                         aopPut(IC_RESULT(ic),"r3",1);
13404                 }
13405                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13406         }
13407         unsavermask(rsave);
13408 }
13409
13410 /*-----------------------------------------------------------------*/
13411 /* genMMDeref -                                                    */
13412 /*-----------------------------------------------------------------*/
13413 static void genMMDeref (iCode *ic,int nparms, operand **parms)
13414 {
13415         bitVect *rsave ;
13416         operand *handle;
13417
13418         assert (nparms == 1);
13419         /* save registers that need to be saved */
13420         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13421                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13422
13423         handle=parms[0];
13424         aopOp (handle,ic,FALSE,FALSE);
13425
13426         /* put the size in R4-R2 */
13427         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13428                 emitcode("push","%s",
13429                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13430                 emitcode("push","%s",
13431                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13432                 emitcode("pop","ar3");
13433                 emitcode("pop","ar2");
13434         } else {
13435                 emitcode ("mov","r2,%s",
13436                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13437                 emitcode ("mov","r3,%s",
13438                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13439         }
13440         freeAsmop (handle, NULL, ic, FALSE);
13441
13442         /* make the call */
13443         emitcode ("lcall","MM_Deref");
13444
13445         {
13446                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13447                 if (rsym->liveFrom != rsym->liveTo) {
13448                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13449                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
13450                             _startLazyDPSEvaluation ();
13451
13452                             aopPut(IC_RESULT(ic),"dpl",0);
13453                             aopPut(IC_RESULT(ic),"dph",1);
13454                             aopPut(IC_RESULT(ic),"dpx",2);
13455
13456                             _endLazyDPSEvaluation ();
13457
13458                         }
13459                 }
13460         }
13461         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13462         unsavermask(rsave);
13463 }
13464
13465 /*-----------------------------------------------------------------*/
13466 /* genMMUnrestrictedPersist -                                      */
13467 /*-----------------------------------------------------------------*/
13468 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
13469 {
13470         bitVect *rsave ;
13471         operand *handle;
13472
13473         assert (nparms == 1);
13474         /* save registers that need to be saved */
13475         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13476                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13477
13478         handle=parms[0];
13479         aopOp (handle,ic,FALSE,FALSE);
13480
13481         /* put the size in R3-R2 */
13482         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13483                 emitcode("push","%s",
13484                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13485                 emitcode("push","%s",
13486                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13487                 emitcode("pop","ar3");
13488                 emitcode("pop","ar2");
13489         } else {
13490                 emitcode ("mov","r2,%s",
13491                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13492                 emitcode ("mov","r3,%s",
13493                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13494         }
13495         freeAsmop (handle, NULL, ic, FALSE);
13496
13497         /* make the call */
13498         emitcode ("lcall","MM_UnrestrictedPersist");
13499
13500         {
13501                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13502                 if (rsym->liveFrom != rsym->liveTo) {
13503                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13504                         aopPut(IC_RESULT(ic),"a",0);
13505                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13506                 }
13507         }
13508         unsavermask(rsave);
13509 }
13510
13511 /*-----------------------------------------------------------------*/
13512 /* genSystemExecJavaProcess -                                      */
13513 /*-----------------------------------------------------------------*/
13514 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
13515 {
13516         bitVect *rsave ;
13517         operand *handle, *pp;
13518
13519         assert (nparms==2);
13520         /* save registers that need to be saved */
13521         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13522                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13523
13524         pp = parms[0];
13525         handle = parms[1];
13526
13527         /* put the handle in R3-R2 */
13528         aopOp (handle,ic,FALSE,FALSE);
13529         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
13530                 emitcode("push","%s",
13531                          aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13532                 emitcode("push","%s",
13533                          aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13534                 emitcode("pop","ar3");
13535                 emitcode("pop","ar2");
13536         } else {
13537                 emitcode ("mov","r2,%s",
13538                           aopGet(handle,0,FALSE,TRUE,DP2_RESULT_REG));
13539                 emitcode ("mov","r3,%s",
13540                           aopGet(handle,1,FALSE,TRUE,DP2_RESULT_REG));
13541         }
13542         freeAsmop (handle, NULL, ic, FALSE);
13543
13544         /* put pointer in DPTR */
13545         aopOp (pp,ic,FALSE,FALSE);
13546         if (AOP_TYPE(pp) == AOP_IMMD) {
13547                 emitcode ("mov", "dptr,%s",
13548                           aopGet (pp, 0, TRUE, FALSE, NULL));
13549         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
13550                 emitcode ("mov","dpl,%s",aopGet(pp,0,FALSE,FALSE,NULL));
13551                 emitcode ("mov","dph,%s",aopGet(pp,1,FALSE,FALSE,NULL));
13552                 emitcode ("mov","dpx,%s",aopGet(pp,2,FALSE,FALSE,NULL));
13553         }
13554         freeAsmop (handle, NULL, ic, FALSE);
13555
13556         /* make the call */
13557         emitcode ("lcall","System_ExecJavaProcess");
13558
13559         /* put result in place */
13560         {
13561                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13562                 if (rsym->liveFrom != rsym->liveTo) {
13563                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13564                         aopPut(IC_RESULT(ic),"a",0);
13565                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13566                 }
13567         }
13568
13569         unsavermask(rsave);
13570 }
13571
13572 /*-----------------------------------------------------------------*/
13573 /* genSystemRTCRegisters -                                         */
13574 /*-----------------------------------------------------------------*/
13575 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
13576                                   char *name)
13577 {
13578         bitVect *rsave ;
13579         operand *pp;
13580
13581         assert (nparms==1);
13582         /* save registers that need to be saved */
13583         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13584                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13585
13586         pp=parms[0];
13587         /* put pointer in DPTR */
13588         aopOp (pp,ic,FALSE,FALSE);
13589         if (AOP_TYPE (pp) == AOP_IMMD) {
13590                 emitcode ("mov","dps,#1");
13591                 emitcode ("mov", "dptr,%s",
13592                           aopGet (pp, 0, TRUE, FALSE, NULL));
13593                 emitcode ("mov","dps,#0");
13594         } else {
13595                 emitcode ("mov","dpl1,%s",
13596                           aopGet(pp,0,FALSE,FALSE,DP2_RESULT_REG));
13597                 emitcode ("mov","dph1,%s",
13598                           aopGet(pp,1,FALSE,FALSE,DP2_RESULT_REG));
13599                 emitcode ("mov","dpx1,%s",
13600                           aopGet(pp,2,FALSE,FALSE,DP2_RESULT_REG));
13601         }
13602         freeAsmop (pp, NULL, ic, FALSE);
13603
13604         /* make the call */
13605         emitcode ("lcall","System_%sRTCRegisters",name);
13606
13607         unsavermask(rsave);
13608 }
13609
13610 /*-----------------------------------------------------------------*/
13611 /* genSystemThreadSleep -                                          */
13612 /*-----------------------------------------------------------------*/
13613 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
13614 {
13615         bitVect *rsave ;
13616         operand *to, *s;
13617
13618         assert (nparms==1);
13619         /* save registers that need to be saved */
13620         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13621                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13622
13623         to = parms[0];
13624         aopOp(to,ic,FALSE,FALSE);
13625         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
13626             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
13627                 emitcode ("push","%s",
13628                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13629                 emitcode ("push","%s",
13630                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13631                 emitcode ("push","%s",
13632                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13633                 emitcode ("push","%s",
13634                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13635                 emitcode ("pop","ar3");
13636                 emitcode ("pop","ar2");
13637                 emitcode ("pop","ar1");
13638                 emitcode ("pop","ar0");
13639         } else {
13640                 emitcode ("mov","r0,%s",
13641                           aopGet(to,0,FALSE,TRUE,DP2_RESULT_REG));
13642                 emitcode ("mov","r1,%s",
13643                           aopGet(to,1,FALSE,TRUE,DP2_RESULT_REG));
13644                 emitcode ("mov","r2,%s",
13645                           aopGet(to,2,FALSE,TRUE,DP2_RESULT_REG));
13646                 emitcode ("mov","r3,%s",
13647                           aopGet(to,3,FALSE,TRUE,DP2_RESULT_REG));
13648         }
13649         freeAsmop (to, NULL, ic, FALSE);
13650
13651         /* suspend in acc */
13652         s = parms[1];
13653         aopOp(s,ic,FALSE,FALSE);
13654         emitcode ("mov","a,%s",
13655                   aopGet(s,0,FALSE,TRUE,NULL));
13656         freeAsmop (s, NULL, ic, FALSE);
13657
13658         /* make the call */
13659         emitcode ("lcall","System_%s",name);
13660
13661         unsavermask(rsave);
13662 }
13663
13664 /*-----------------------------------------------------------------*/
13665 /* genSystemThreadResume -                                         */
13666 /*-----------------------------------------------------------------*/
13667 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13668 {
13669         bitVect *rsave ;
13670         operand *tid,*pid;
13671
13672         assert (nparms==2);
13673         /* save registers that need to be saved */
13674         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13675                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13676
13677         tid = parms[0];
13678         pid = parms[1];
13679
13680         /* PID in R0 */
13681         aopOp(pid,ic,FALSE,FALSE);
13682         emitcode ("mov","r0,%s",
13683                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13684         freeAsmop (pid, NULL, ic, FALSE);
13685
13686         /* tid into ACC */
13687         aopOp(tid,ic,FALSE,FALSE);
13688         emitcode ("mov","a,%s",
13689                   aopGet(tid,0,FALSE,TRUE,DP2_RESULT_REG));
13690         freeAsmop (tid, NULL, ic, FALSE);
13691
13692         emitcode ("lcall","System_ThreadResume");
13693
13694         /* put result into place */
13695         {
13696                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13697                 if (rsym->liveFrom != rsym->liveTo) {
13698                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13699                         aopPut(IC_RESULT(ic),"a",0);
13700                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13701                 }
13702         }
13703         unsavermask(rsave);
13704 }
13705
13706 /*-----------------------------------------------------------------*/
13707 /* genSystemProcessResume -                                        */
13708 /*-----------------------------------------------------------------*/
13709 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13710 {
13711         bitVect *rsave ;
13712         operand *pid;
13713
13714         assert (nparms==1);
13715         /* save registers that need to be saved */
13716         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13717                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13718
13719         pid = parms[0];
13720
13721         /* pid into ACC */
13722         aopOp(pid,ic,FALSE,FALSE);
13723         emitcode ("mov","a,%s",
13724                   aopGet(pid,0,FALSE,TRUE,DP2_RESULT_REG));
13725         freeAsmop (pid, NULL, ic, FALSE);
13726
13727         emitcode ("lcall","System_ProcessResume");
13728
13729         unsavermask(rsave);
13730 }
13731
13732 /*-----------------------------------------------------------------*/
13733 /* genSystem -                                                     */
13734 /*-----------------------------------------------------------------*/
13735 static void genSystem (iCode *ic,int nparms,char *name)
13736 {
13737         assert(nparms == 0);
13738
13739         emitcode ("lcall","System_%s",name);
13740 }
13741
13742 /*-----------------------------------------------------------------*/
13743 /* genSystemPoll -                                                  */
13744 /*-----------------------------------------------------------------*/
13745 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13746 {
13747         bitVect *rsave ;
13748         operand *fp;
13749
13750         assert (nparms==1);
13751         /* save registers that need to be saved */
13752         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13753                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13754
13755         fp = parms[0];
13756         aopOp (fp,ic,FALSE,FALSE);
13757         if (AOP_TYPE (fp) == AOP_IMMD) {
13758                 emitcode ("mov", "dptr,%s",
13759                           aopGet (fp, 0, TRUE, FALSE, DP2_RESULT_REG));
13760         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13761                 emitcode ("mov","dpl,%s",
13762                           aopGet(fp,0,FALSE,FALSE,DP2_RESULT_REG));
13763                 emitcode ("mov","dph,%s",
13764                           aopGet(fp,1,FALSE,FALSE,DP2_RESULT_REG));
13765                 emitcode ("mov","dpx,%s",
13766                           aopGet(fp,2,FALSE,FALSE,DP2_RESULT_REG));
13767         }
13768         freeAsmop (fp, NULL, ic, FALSE);
13769
13770         emitcode ("lcall","System_%sPoll",name);
13771
13772         /* put result into place */
13773         {
13774                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13775                 if (rsym->liveFrom != rsym->liveTo) {
13776                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13777                         aopPut(IC_RESULT(ic),"a",0);
13778                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13779                 }
13780         }
13781         unsavermask(rsave);
13782 }
13783
13784 /*-----------------------------------------------------------------*/
13785 /* genSystemGetCurrentID -                                         */
13786 /*-----------------------------------------------------------------*/
13787 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13788 {
13789         assert (nparms==0);
13790
13791         emitcode ("lcall","System_GetCurrent%sId",name);
13792         /* put result into place */
13793         {
13794                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13795                 if (rsym->liveFrom != rsym->liveTo) {
13796                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13797                         aopPut(IC_RESULT(ic),"a",0);
13798                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13799                 }
13800         }
13801 }
13802
13803 /*-----------------------------------------------------------------*/
13804 /* genDjnz - generate decrement & jump if not zero instrucion      */
13805 /*-----------------------------------------------------------------*/
13806 static int
13807 genDjnz (iCode * ic, iCode * ifx)
13808 {
13809   symbol *lbl, *lbl1;
13810   if (!ifx)
13811     return 0;
13812
13813   /* if the if condition has a false label
13814      then we cannot save */
13815   if (IC_FALSE (ifx))
13816     return 0;
13817
13818   /* if the minus is not of the form a = a - 1 */
13819   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
13820       !IS_OP_LITERAL (IC_RIGHT (ic)))
13821     return 0;
13822
13823   if (operandLitValue (IC_RIGHT (ic)) != 1)
13824     return 0;
13825
13826   /* if the size of this greater than one then no
13827      saving */
13828   if (getSize (operandType (IC_RESULT (ic))) > 1)
13829     return 0;
13830
13831   /* otherwise we can save BIG */
13832
13833   D (emitcode (";", "genDjnz"));
13834
13835   lbl = newiTempLabel (NULL);
13836   lbl1 = newiTempLabel (NULL);
13837
13838   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13839
13840   if (AOP_NEEDSACC(IC_RESULT(ic)))
13841   {
13842       /* If the result is accessed indirectly via
13843        * the accumulator, we must explicitly write
13844        * it back after the decrement.
13845        */
13846       char *rByte = aopGet (IC_RESULT(ic), 0, FALSE, FALSE, NULL);
13847
13848       if (strcmp(rByte, "a"))
13849       {
13850            /* Something is hopelessly wrong */
13851            fprintf(stderr, "*** warning: internal error at %s:%d\n",
13852                    __FILE__, __LINE__);
13853            /* We can just give up; the generated code will be inefficient,
13854             * but what the hey.
13855             */
13856            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13857            return 0;
13858       }
13859       emitcode ("dec", "%s", rByte);
13860       aopPut (IC_RESULT (ic), rByte, 0);
13861       emitcode ("jnz", "!tlabel", lbl->key + 100);
13862   }
13863   else if (IS_AOP_PREG (IC_RESULT (ic)))
13864     {
13865       emitcode ("dec", "%s",
13866                 aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13867       MOVA (aopGet (IC_RESULT (ic), 0, FALSE, FALSE, NULL));
13868       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13869       ifx->generated = 1;
13870       emitcode ("jnz", "!tlabel", lbl->key + 100);
13871     }
13872   else
13873     {
13874       emitcode ("djnz", "%s,!tlabel", aopGet (IC_RESULT (ic), 0, FALSE, TRUE, NULL),
13875                 lbl->key + 100);
13876     }
13877   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
13878   emitLabel (lbl);
13879   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
13880   emitLabel (lbl1);
13881
13882   if (!ifx->generated)
13883       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13884   ifx->generated = 1;
13885   return 1;
13886 }
13887
13888 /*-----------------------------------------------------------------*/
13889 /* genReceive - generate code for a receive iCode                  */
13890 /*-----------------------------------------------------------------*/
13891 static void
13892 genReceive (iCode * ic)
13893 {
13894     int size = getSize (operandType (IC_RESULT (ic)));
13895     int offset = 0;
13896     int rb1off ;
13897
13898     D (emitcode (";", "genReceive"));
13899
13900     if (ic->argreg == 1)
13901     {
13902         /* first parameter */
13903         if (AOP_IS_STR(IC_RESULT(ic)))
13904         {
13905             /* Nothing to do: it's already in the proper place. */
13906             return;
13907         }
13908         else
13909         {
13910             bool useDp2;
13911
13912             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
13913                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
13914                  IS_TRUE_SYMOP (IC_RESULT (ic)));
13915
13916             _G.accInUse++;
13917             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
13918             _G.accInUse--;
13919
13920             /* Sanity checking... */
13921             if (AOP_USESDPTR(IC_RESULT(ic)))
13922             {
13923                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13924                         "genReceive got unexpected DPTR.");
13925             }
13926             assignResultValue (IC_RESULT (ic), NULL);
13927         }
13928     }
13929     else if (ic->argreg > 12)
13930     { /* bit parameters */
13931       if (OP_SYMBOL (IC_RESULT (ic))->regs[0]->rIdx != ic->argreg-5)
13932         {
13933           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13934           emitcode ("mov", "c,%s", rb1regs[ic->argreg-5]);
13935           outBitC(IC_RESULT (ic));
13936         }
13937     }
13938     else
13939     {
13940         /* second receive onwards */
13941         /* this gets a little tricky since unused receives will be
13942          eliminated, we have saved the reg in the type field . and
13943          we use that to figure out which register to use */
13944         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
13945         rb1off = ic->argreg;
13946         while (size--)
13947         {
13948             aopPut (IC_RESULT (ic), rb1regs[rb1off++ -5], offset++);
13949         }
13950     }
13951     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13952 }
13953
13954 /*-----------------------------------------------------------------*/
13955 /* genDummyRead - generate code for dummy read of volatiles        */
13956 /*-----------------------------------------------------------------*/
13957 static void
13958 genDummyRead (iCode * ic)
13959 {
13960   operand *op;
13961   int size, offset;
13962
13963   D (emitcode(";", "genDummyRead"));
13964
13965   op = IC_RIGHT (ic);
13966   if (op && IS_SYMOP (op))
13967     {
13968       aopOp (op, ic, FALSE, FALSE);
13969
13970       /* if the result is a bit */
13971       if (AOP_TYPE (op) == AOP_CRY)
13972         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13973       else
13974         {
13975           /* bit variables done */
13976           /* general case */
13977           size = AOP_SIZE (op);
13978           offset = 0;
13979           while (size--)
13980           {
13981             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
13982             offset++;
13983           }
13984         }
13985
13986       freeAsmop (op, NULL, ic, TRUE);
13987     }
13988
13989   op = IC_LEFT (ic);
13990   if (op && IS_SYMOP (op))
13991     {
13992       aopOp (op, ic, FALSE, FALSE);
13993
13994       /* if the result is a bit */
13995       if (AOP_TYPE (op) == AOP_CRY)
13996         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13997       else
13998         {
13999           /* bit variables done */
14000           /* general case */
14001           size = AOP_SIZE (op);
14002           offset = 0;
14003           while (size--)
14004           {
14005             MOVA (aopGet (op, offset, FALSE, FALSE, FALSE));
14006             offset++;
14007           }
14008         }
14009
14010       freeAsmop (op, NULL, ic, TRUE);
14011     }
14012 }
14013
14014 /*-----------------------------------------------------------------*/
14015 /* genCritical - generate code for start of a critical sequence    */
14016 /*-----------------------------------------------------------------*/
14017 static void
14018 genCritical (iCode *ic)
14019 {
14020   symbol *tlbl = newiTempLabel (NULL);
14021
14022   D (emitcode(";", "genCritical"));
14023
14024   if (IC_RESULT (ic))
14025     {
14026       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
14027       aopPut (IC_RESULT (ic), one, 0); /* save old ea in an operand */
14028       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14029       aopPut (IC_RESULT (ic), zero, 0);
14030       emitLabel (tlbl);
14031       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
14032     }
14033   else
14034     {
14035       emitcode ("setb", "c");
14036       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
14037       emitcode ("clr", "c");
14038       emitLabel (tlbl);
14039       emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
14040     }
14041 }
14042
14043 /*-----------------------------------------------------------------*/
14044 /* genEndCritical - generate code for end of a critical sequence   */
14045 /*-----------------------------------------------------------------*/
14046 static void
14047 genEndCritical (iCode *ic)
14048 {
14049   D(emitcode(";", "genEndCritical"));
14050
14051   if (IC_RIGHT (ic))
14052     {
14053       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
14054       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
14055         {
14056           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
14057           emitcode ("mov", "ea,c");
14058         }
14059       else
14060         {
14061           MOVA (aopGet (IC_RIGHT (ic), 0, FALSE, FALSE, FALSE));
14062           emitcode ("rrc", "a");
14063           emitcode ("mov", "ea,c");
14064         }
14065       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
14066     }
14067   else
14068     {
14069       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
14070       emitcode ("mov", "ea,c");
14071     }
14072 }
14073
14074
14075
14076 /*-----------------------------------------------------------------*/
14077 /* genBuiltIn - calls the appropriate function to  generating code */
14078 /* for a built in function                                         */
14079 /*-----------------------------------------------------------------*/
14080 static void genBuiltIn (iCode *ic)
14081 {
14082         operand *bi_parms[MAX_BUILTIN_ARGS];
14083         int nbi_parms;
14084         iCode *bi_iCode;
14085         symbol *bif;
14086
14087         /* get all the arguments for a built in function */
14088         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
14089
14090         /* which function is it */
14091         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
14092         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
14093                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
14094         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
14095                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
14096         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
14097                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
14098         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
14099                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
14100         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
14101                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
14102         } else if (strcmp(bif->name,"__builtin_inp")==0) {
14103                 genInp(bi_iCode,nbi_parms,bi_parms);
14104         } else if (strcmp(bif->name,"__builtin_outp")==0) {
14105                 genOutp(bi_iCode,nbi_parms,bi_parms);
14106         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
14107                 genSwapW(bi_iCode,nbi_parms,bi_parms);
14108                 /* JavaNative builtIns */
14109         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
14110                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
14111         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
14112                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
14113         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
14114                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
14115         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
14116                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
14117         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
14118                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14119         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
14120                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14121         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
14122                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
14123         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
14124                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
14125         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
14126                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
14127         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
14128                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
14129         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
14130                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
14131         } else if (strcmp(bif->name,"MM_Malloc")==0) {
14132                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
14133         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
14134                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
14135         } else if (strcmp(bif->name,"MM_Free")==0) {
14136                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
14137         } else if (strcmp(bif->name,"MM_Deref")==0) {
14138                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
14139         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
14140                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
14141         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
14142                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
14143         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
14144                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
14145         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
14146                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
14147         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
14148                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
14149         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
14150                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
14151         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
14152                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
14153         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
14154                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
14155         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14156                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14157         } else if (strcmp(bif->name,"System_SaveThread")==0) {
14158                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14159         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
14160                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
14161         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
14162                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
14163         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
14164                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
14165         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
14166                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
14167         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
14168                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
14169         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
14170                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
14171         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
14172                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
14173         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
14174                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
14175         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
14176                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
14177         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
14178                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
14179         } else {
14180                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
14181                 return ;
14182         }
14183         return ;
14184 }
14185
14186 /*-----------------------------------------------------------------*/
14187 /* gen390Code - generate code for Dallas 390 based controllers     */
14188 /*-----------------------------------------------------------------*/
14189 void
14190 gen390Code (iCode * lic)
14191 {
14192   iCode *ic;
14193   int cln = 0;
14194
14195   _G.currentFunc = NULL;
14196   lineHead = lineCurr = NULL;
14197   dptrn[1][0] = "dpl1";
14198   dptrn[1][1] = "dph1";
14199   dptrn[1][2] = "dpx1";
14200
14201   if (options.model == MODEL_FLAT24) {
14202     fReturnSizeDS390 = 5;
14203     fReturn = fReturn24;
14204   } else {
14205     fReturnSizeDS390 = 4;
14206     fReturn = fReturn16;
14207     options.stack10bit=0;
14208   }
14209 #if 1
14210   /* print the allocation information */
14211   if (allocInfo && currFunc)
14212     printAllocInfo (currFunc, codeOutBuf);
14213 #endif
14214   /* if debug information required */
14215   if (options.debug && currFunc)
14216     {
14217       debugFile->writeFunction (currFunc, lic);
14218     }
14219   /* stack pointer name */
14220   if (options.useXstack)
14221     spname = "_spx";
14222   else
14223     spname = "sp";
14224
14225
14226   for (ic = lic; ic; ic = ic->next)
14227     {
14228       _G.current_iCode = ic;
14229
14230       if (ic->lineno && cln != ic->lineno)
14231         {
14232           if (options.debug)
14233             {
14234               debugFile->writeCLine (ic);
14235             }
14236           if (!options.noCcodeInAsm) {
14237             emitcode (";", "%s:%d: %s", ic->filename, ic->lineno,
14238                       printCLine(ic->filename, ic->lineno));
14239           }
14240           cln = ic->lineno;
14241         }
14242       if (options.iCodeInAsm) {
14243         char *iLine = printILine(ic);
14244         emitcode(";", "ic:%d: %s", ic->key, iLine);
14245         dbuf_free(iLine);
14246       }
14247       /* if the result is marked as
14248          spilt and rematerializable or code for
14249          this has already been generated then
14250          do nothing */
14251       if (resultRemat (ic) || ic->generated)
14252         continue;
14253
14254       /* depending on the operation */
14255       switch (ic->op)
14256         {
14257         case '!':
14258           genNot (ic);
14259           break;
14260
14261         case '~':
14262           genCpl (ic);
14263           break;
14264
14265         case UNARYMINUS:
14266           genUminus (ic);
14267           break;
14268
14269         case IPUSH:
14270           genIpush (ic);
14271           break;
14272
14273         case IPOP:
14274           /* IPOP happens only when trying to restore a
14275              spilt live range, if there is an ifx statement
14276              following this pop then the if statement might
14277              be using some of the registers being popped which
14278              would destory the contents of the register so
14279              we need to check for this condition and handle it */
14280           if (ic->next &&
14281               ic->next->op == IFX &&
14282               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
14283             genIfx (ic->next, ic);
14284           else
14285             genIpop (ic);
14286           break;
14287
14288         case CALL:
14289           genCall (ic);
14290           break;
14291
14292         case PCALL:
14293           genPcall (ic);
14294           break;
14295
14296         case FUNCTION:
14297           genFunction (ic);
14298           break;
14299
14300         case ENDFUNCTION:
14301           genEndFunction (ic);
14302           break;
14303
14304         case RETURN:
14305           genRet (ic);
14306           break;
14307
14308         case LABEL:
14309           genLabel (ic);
14310           break;
14311
14312         case GOTO:
14313           genGoto (ic);
14314           break;
14315
14316         case '+':
14317           genPlus (ic);
14318           break;
14319
14320         case '-':
14321           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
14322             genMinus (ic);
14323           break;
14324
14325         case '*':
14326           genMult (ic);
14327           break;
14328
14329         case '/':
14330           genDiv (ic);
14331           break;
14332
14333         case '%':
14334           genMod (ic);
14335           break;
14336
14337         case '>':
14338           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
14339           break;
14340
14341         case '<':
14342           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
14343           break;
14344
14345         case LE_OP:
14346         case GE_OP:
14347         case NE_OP:
14348
14349           /* note these two are xlated by algebraic equivalence
14350              during parsing SDCC.y */
14351           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
14352                   "got '>=' or '<=' shouldn't have come here");
14353           break;
14354
14355         case EQ_OP:
14356           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
14357           break;
14358
14359         case AND_OP:
14360           genAndOp (ic);
14361           break;
14362
14363         case OR_OP:
14364           genOrOp (ic);
14365           break;
14366
14367         case '^':
14368           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
14369           break;
14370
14371         case '|':
14372           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
14373           break;
14374
14375         case BITWISEAND:
14376           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
14377           break;
14378
14379         case INLINEASM:
14380           genInline (ic);
14381           break;
14382
14383         case RRC:
14384           genRRC (ic);
14385           break;
14386
14387         case RLC:
14388           genRLC (ic);
14389           break;
14390
14391         case GETHBIT:
14392           genGetHbit (ic);
14393           break;
14394
14395         case LEFT_OP:
14396           genLeftShift (ic);
14397           break;
14398
14399         case RIGHT_OP:
14400           genRightShift (ic);
14401           break;
14402
14403         case GET_VALUE_AT_ADDRESS:
14404           genPointerGet (ic,
14405                          hasInc (IC_LEFT (ic), ic,
14406                                  getSize (operandType (IC_RESULT (ic)))));
14407           break;
14408
14409         case '=':
14410           if (POINTER_SET (ic))
14411             genPointerSet (ic,
14412                            hasInc (IC_RESULT (ic), ic,
14413                                    getSize (operandType (IC_RIGHT (ic)))));
14414           else
14415             genAssign (ic);
14416           break;
14417
14418         case IFX:
14419           genIfx (ic, NULL);
14420           break;
14421
14422         case ADDRESS_OF:
14423           genAddrOf (ic);
14424           break;
14425
14426         case JUMPTABLE:
14427           genJumpTab (ic);
14428           break;
14429
14430         case CAST:
14431           genCast (ic);
14432           break;
14433
14434         case RECEIVE:
14435           genReceive (ic);
14436           break;
14437
14438         case SEND:
14439           if (ic->builtinSEND)
14440             genBuiltIn(ic);
14441           else
14442             addSet (&_G.sendSet, ic);
14443           break;
14444
14445         case DUMMY_READ_VOLATILE:
14446           genDummyRead (ic);
14447           break;
14448
14449         case CRITICAL:
14450           genCritical (ic);
14451           break;
14452
14453         case ENDCRITICAL:
14454           genEndCritical (ic);
14455           break;
14456
14457         case SWAP:
14458           genSwap (ic);
14459           break;
14460
14461 #if 0 // obsolete, and buggy for != xdata
14462         case ARRAYINIT:
14463             genArrayInit(ic);
14464             break;
14465 #endif
14466
14467         default:
14468             /* This should never happen, right? */
14469             fprintf(stderr, "*** Probable error: unsupported op 0x%x (%c) in %s @ %d\n", 
14470                     ic->op, ic->op, __FILE__, __LINE__);
14471             ic = ic;
14472         }
14473     }
14474
14475
14476   /* now we are ready to call the
14477      peep hole optimizer */
14478   if (!options.nopeep)
14479     peepHole (&lineHead);
14480
14481   /* now do the actual printing */
14482   printLine (lineHead, codeOutBuf);
14483   return;
14484 }