6abd6a6db6e9c3fda2ded067eec6a7b0c0ef6341
[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 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <ctype.h>
32
33 #include "common.h"
34 #include "main.h"
35 #include "ralloc.h"
36 #include "gen.h"
37 #include "SDCCglobl.h"
38 #include "newalloc.h"
39
40 #define BETTER_LITERAL_SHIFT
41
42 char *aopLiteral (value * val, int offset);
43 extern int allocInfo;
44
45 /* this is the down and dirty file with all kinds of
46    kludgy & hacky stuff. This is what it is all about
47    CODE GENERATION for a specific MCU . some of the
48    routines may be reusable, will have to see */
49
50 static char *zero = "#0";
51 static char *one = "#1";
52 static char *spname;
53
54 #define D(x) x
55
56 #define TR_DPTR(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_DPTR1 %s ", s); }
57 #define TR_AP(s) if (options.model != MODEL_FLAT24) { emitcode(";", " Use_AP %s ", s); }
58
59 short fReturnSizeDS390 = 5;
60 static char *fReturn24[] =
61 {"dpl", "dph", "dpx", "b", "a"};
62 static char *fReturn16[] =
63 {"dpl", "dph", "b", "a"};
64 static char **fReturn = fReturn24;
65 static char *accUse[] =
66 {"a", "b"};
67 static char *dptrn[2][3];
68 static char *javaRet[] = { "r0","r1","r2","r3"};
69 static short rbank = -1;
70
71 static struct
72   {
73     short r0Pushed;
74     short r1Pushed;
75     short accInUse;
76     short bInUse;
77     short inLine;
78     short debugLine;
79     short nRegsSaved;
80     short dptrInUse;
81     short dptr1InUse;
82     set *sendSet;
83     iCode *current_iCode;
84   }
85 _G;
86
87 static char *rb1regs[] = {
88     "b1_0","b1_1","b1_2","b1_3","b1_4","b1_5","b1_6","b1_7"
89 };
90
91 static void saveRBank (int, iCode *, bool);
92
93 #define RESULTONSTACK(x) \
94                          (IC_RESULT(x) && IC_RESULT(x)->aop && \
95                          IC_RESULT(x)->aop->type == AOP_STK )
96
97 #define MOVA(x) _movA(x)
98 #define MOVB(x) _movB(x)
99
100 #define CLRC    emitcode("clr","c")
101 #define SETC    emitcode("setb","c")
102
103 // A scratch register which will be used to hold
104 // result bytes from operands in far space via DPTR2.
105 #define DP2_RESULT_REG  "_ap"
106
107 static lineNode *lineHead = NULL;
108 static lineNode *lineCurr = NULL;
109
110 static unsigned char SLMask[] =
111 {0xFF, 0xFE, 0xFC, 0xF8, 0xF0,
112  0xE0, 0xC0, 0x80, 0x00};
113 static unsigned char SRMask[] =
114 {0xFF, 0x7F, 0x3F, 0x1F, 0x0F,
115  0x07, 0x03, 0x01, 0x00};
116
117 #define LSB     0
118 #define MSB16   1
119 #define MSB24   2
120 #define MSB32   3
121 #define PROTECT_SP      {if (options.protect_sp_update) {                       \
122                                 symbol *lbl = newiTempLabel(NULL);              \
123                                 emitcode ("setb","F1");                         \
124                                 emitcode ("jbc","EA,!tlabel",lbl->key+100);     \
125                                 emitcode ("clr","F1");                          \
126                                 emitcode ("","!tlabeldef",lbl->key+100);        \
127                         }}
128 #define UNPROTECT_SP    { if (options.protect_sp_update) {                      \
129                                 symbol *lbl = newiTempLabel(NULL);              \
130                                 emitcode ("jnb","F1,!tlabel",lbl->key+100);     \
131                                 emitcode ("setb","EA");                         \
132                                 emitcode ("","!tlabeldef",lbl->key+100);        \
133                         }}
134
135 static int _currentDPS;         /* Current processor DPS. */
136 static int _desiredDPS;         /* DPS value compiler thinks we should be using. */
137 static int _lazyDPS = 0;        /* if non-zero, we are doing lazy evaluation of DPS changes. */
138
139 /*-----------------------------------------------------------------*/
140 /* emitcode - writes the code into a file : for now it is simple    */
141 /*-----------------------------------------------------------------*/
142 static void
143 emitcode (char *inst, char *fmt,...)
144 {
145     va_list ap;
146     char lb[INITIAL_INLINEASM];
147     char *lbp = lb;
148
149     va_start (ap, fmt);
150
151     if (inst && *inst)
152     {
153         if (fmt && *fmt)
154         {
155             SNPRINTF (lb, sizeof(lb), "%s\t", inst);
156         }
157         else
158         {
159             SNPRINTF (lb, sizeof(lb), "%s", inst);
160         }
161
162         tvsprintf (lb + strlen(lb), sizeof(lb) - strlen(lb),
163                    fmt, ap);
164     }
165     else
166     {
167         tvsprintf (lb, sizeof(lb), fmt, ap);
168     }
169
170
171     while (isspace (*lbp))
172     {
173         lbp++;
174     }
175
176     if (lbp && *lbp)
177     {
178         lineCurr = (lineCurr ?
179                     connectLine (lineCurr, newLineNode (lb)) :
180                     (lineHead = newLineNode (lb)));
181     }
182
183     lineCurr->isInline = _G.inLine;
184     lineCurr->isDebug = _G.debugLine;
185     lineCurr->ic = _G.current_iCode;
186     lineCurr->aln = ds390newAsmLineNode(_currentDPS);
187     va_end (ap);
188 }
189
190 /*-----------------------------------------------------------------*/
191 /* ds390_emitDebuggerSymbol - associate the current code location  */
192 /*   with a debugger symbol                                        */
193 /*-----------------------------------------------------------------*/
194 void
195 ds390_emitDebuggerSymbol (char * debugSym)
196 {
197   _G.debugLine = 1;
198   emitcode ("", "%s ==.", debugSym);
199   _G.debugLine = 0;
200 }
201
202 //
203 // Move the passed value into A unless it is already there.
204 //
205 static void
206 _movA(const char *s)
207 {
208     if (strcmp(s,"a") && strcmp(s,"acc"))
209     {
210         emitcode("mov","a,%s",s);
211     }
212 }
213
214 //
215 // Move the passed value into B unless it is already there.
216 //
217 static void
218 _movB(const char *s)
219 {
220     if (strcmp(s,"b"))
221     {
222         emitcode("mov","b,%s",s);
223     }
224 }
225
226 /*-----------------------------------------------------------------*/
227 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
228 /*-----------------------------------------------------------------*/
229 static regs *
230 getFreePtr (iCode * ic, asmop ** aopp, bool result)
231 {
232   bool r0iu, r1iu;
233   bool r0ou, r1ou;
234
235   /* the logic: if r0 & r1 used in the instruction
236      then we are in trouble otherwise */
237
238   /* first check if r0 & r1 are used by this
239      instruction, in which case we are in trouble */
240   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
241   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
242   if (r0iu && r1iu) {
243       goto endOfWorld;
244     }
245
246   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
247   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
248
249   /* if no usage of r0 then return it */
250   if (!r0iu && !r0ou)
251     {
252       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
253       (*aopp)->type = AOP_R0;
254
255       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
256     }
257
258   /* if no usage of r1 then return it */
259   if (!r1iu && !r1ou)
260     {
261       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
262       (*aopp)->type = AOP_R1;
263
264       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R1_IDX);
265     }
266
267   /* now we know they both have usage */
268   /* if r0 not used in this instruction */
269   if (!r0iu)
270     {
271       /* push it if not already pushed */
272       if (!_G.r0Pushed)
273         {
274           emitcode ("push", "%s",
275                     ds390_regWithIdx (R0_IDX)->dname);
276           _G.r0Pushed++;
277         }
278
279       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
280       (*aopp)->type = AOP_R0;
281
282       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
283     }
284
285   /* if r1 not used then */
286
287   if (!r1iu)
288     {
289       /* push it if not already pushed */
290       if (!_G.r1Pushed)
291         {
292           emitcode ("push", "%s",
293                     ds390_regWithIdx (R1_IDX)->dname);
294           _G.r1Pushed++;
295         }
296
297       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
298       (*aopp)->type = AOP_R1;
299       return ds390_regWithIdx (R1_IDX);
300     }
301
302 endOfWorld:
303   /* I said end of world but not quite end of world yet */
304   /* if this is a result then we can push it on the stack */
305   if (result)
306     {
307       (*aopp)->type = AOP_STK;
308       return NULL;
309     }
310
311   /* other wise this is true end of the world */
312   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
313           "getFreePtr should never reach here");
314   exit (1);
315
316   return NULL; // notreached, but makes compiler happy.
317 }
318
319 /*-----------------------------------------------------------------*/
320 /* newAsmop - creates a new asmOp                                  */
321 /*-----------------------------------------------------------------*/
322 static asmop *
323 newAsmop (short type)
324 {
325   asmop *aop;
326
327   aop = Safe_calloc (1, sizeof (asmop));
328   aop->type = type;
329   return aop;
330 }
331
332
333 /*-----------------------------------------------------------------*/
334 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
335 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
336 /* alternate DPTR (DPL1/DPH1/DPX1).          */
337 /*-----------------------------------------------------------------*/
338 static void
339 genSetDPTR (int n)
340 {
341
342   /* If we are doing lazy evaluation, simply note the desired
343    * change, but don't emit any code yet.
344    */
345   if (_lazyDPS)
346     {
347       _desiredDPS = n;
348       return;
349     }
350
351   if (!n)
352     {
353       emitcode ("mov", "dps,#0");
354     }
355   else
356     {
357       TR_DPTR("#1");
358       emitcode ("mov", "dps,#1");
359     }
360 }
361
362 /*-----------------------------------------------------------------*/
363 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
364 /*                   */
365 /* Any code that operates on DPTR (NB: not on the individual     */
366 /* components, like DPH) *must* call _flushLazyDPS() before using  */
367 /* DPTR within a lazy DPS evaluation block.        */
368 /*                   */
369 /* Note that aopPut and aopGet already contain the proper calls to */
370 /* _flushLazyDPS, so it is safe to use these calls within a lazy   */
371 /* DPS evaluation block.             */
372 /*                   */
373 /* Also, _flushLazyDPS must be called before any flow control      */
374 /* operations that could potentially branch out of the block.    */
375 /*                         */
376 /* Lazy DPS evaluation is simply an optimization (though an      */
377 /* important one), so if in doubt, leave it out.       */
378 /*-----------------------------------------------------------------*/
379 static void
380 _startLazyDPSEvaluation (void)
381 {
382   _currentDPS = 0;
383   _desiredDPS = 0;
384 #ifdef BETTER_LITERAL_SHIFT
385   _lazyDPS++;
386 #else
387   _lazyDPS = 1;
388 #endif
389 }
390
391 /*-----------------------------------------------------------------*/
392 /* _flushLazyDPS: emit code to force the actual DPS setting to the */
393 /* desired one. Call before using DPTR within a lazy DPS evaluation */
394 /* block.                */
395 /*-----------------------------------------------------------------*/
396 static void
397 _flushLazyDPS (void)
398 {
399   if (!_lazyDPS)
400     {
401       /* nothing to do. */
402       return;
403     }
404
405   if (_desiredDPS != _currentDPS)
406     {
407       if (_desiredDPS)
408         {
409           emitcode ("inc", "dps");
410         }
411       else
412         {
413           emitcode ("dec", "dps");
414         }
415       _currentDPS = _desiredDPS;
416     }
417 }
418
419 /*-----------------------------------------------------------------*/
420 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.     */
421 /*                   */
422 /* Forces us back to the safe state (standard DPTR selected).    */
423 /*-----------------------------------------------------------------*/
424 static void
425 _endLazyDPSEvaluation (void)
426 {
427 #ifdef BETTER_LITERAL_SHIFT
428   _lazyDPS--;
429 #else
430   _lazyDPS = 0;
431 #endif
432   if (!_lazyDPS)
433   {
434     if (_currentDPS)
435     {
436       genSetDPTR (0);
437       _flushLazyDPS ();
438     }
439     _currentDPS = 0;
440     _desiredDPS = 0;
441   }
442 }
443
444
445
446 /*-----------------------------------------------------------------*/
447 /* pointerCode - returns the code for a pointer type               */
448 /*-----------------------------------------------------------------*/
449 static int
450 pointerCode (sym_link * etype)
451 {
452
453   return PTR_TYPE (SPEC_OCLS (etype));
454
455 }
456
457 /*-----------------------------------------------------------------*/
458 /* leftRightUseAcc - returns size of accumulator use by operands   */
459 /*-----------------------------------------------------------------*/
460 static int
461 leftRightUseAcc(iCode *ic)
462 {
463   operand *op;
464   int size;
465   int accuseSize = 0;
466   int accuse = 0;
467
468   if (!ic)
469     {
470       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
471               "null iCode pointer");
472       return 0;
473     }
474
475   if (ic->op == IFX)
476     {
477       op = IC_COND (ic);
478       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
479         {
480           accuse = 1;
481           size = getSize (OP_SYMBOL (op)->type);
482           if (size>accuseSize)
483             accuseSize = size;
484         }
485     }
486   else if (ic->op == JUMPTABLE)
487     {
488       op = IC_JTCOND (ic);
489       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
490         {
491           accuse = 1;
492           size = getSize (OP_SYMBOL (op)->type);
493           if (size>accuseSize)
494             accuseSize = size;
495         }
496     }
497   else
498     {
499       op = IC_LEFT (ic);
500       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
501         {
502           accuse = 1;
503           size = getSize (OP_SYMBOL (op)->type);
504           if (size>accuseSize)
505             accuseSize = size;
506         }
507       op = IC_RIGHT (ic);
508       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
509         {
510           accuse = 1;
511           size = getSize (OP_SYMBOL (op)->type);
512           if (size>accuseSize)
513             accuseSize = size;
514         }
515     }
516
517   if (accuseSize)
518     return accuseSize;
519   else
520     return accuse;
521 }
522
523 /*-----------------------------------------------------------------*/
524 /* aopForSym - for a true symbol                                   */
525 /*-----------------------------------------------------------------*/
526 static asmop *
527 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
528 {
529   asmop *aop;
530   memmap *space = SPEC_OCLS (sym->etype);
531   int accuse = leftRightUseAcc (ic);
532
533   /* if already has one */
534   if (sym->aop)
535     {
536       if ((sym->aop->type == AOP_DPTR && useDP2)
537           || (sym->aop->type == AOP_DPTR2 && !useDP2))
538         sym->aop = NULL;
539       else
540         return sym->aop;
541     }
542
543   /* assign depending on the storage class */
544   /* if it is on the stack or indirectly addressable */
545   /* space we need to assign either r0 or r1 to it   */
546   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
547     {
548       sym->aop = aop = newAsmop (0);
549       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
550       aop->size = getSize (sym->type);
551
552       /* now assign the address of the variable to
553          the pointer register */
554       if (aop->type != AOP_STK)
555         {
556
557           if (sym->onStack)
558             {
559               if (_G.accInUse || accuse)
560                 emitcode ("push", "acc");
561
562               if (_G.bInUse || (accuse>1))
563                 emitcode ("push", "b");
564
565               emitcode ("mov", "a,_bp");
566               emitcode ("add", "a,#!constbyte",
567                         ((sym->stack < 0) ?
568                          ((char) (sym->stack - _G.nRegsSaved)) :
569                          ((char) sym->stack)) & 0xff);
570               emitcode ("mov", "%s,a",
571                         aop->aopu.aop_ptr->name);
572
573               if (_G.bInUse || (accuse>1))
574                 emitcode ("pop", "b");
575
576               if (_G.accInUse || accuse)
577                 emitcode ("pop", "acc");
578             }
579           else
580             emitcode ("mov", "%s,#%s",
581                       aop->aopu.aop_ptr->name,
582                       sym->rname);
583           aop->paged = space->paged;
584         }
585       else
586         aop->aopu.aop_stk = sym->stack;
587       return aop;
588     }
589
590   if (sym->onStack && options.stack10bit)
591     {
592         short stack_val = -((sym->stack < 0) ?
593                             ((short) (sym->stack - _G.nRegsSaved)) :
594                             ((short) sym->stack)) ;
595         if (useDP2 && _G.dptr1InUse) {
596             emitcode ("push","dpl1");
597             emitcode ("push","dph1");
598             emitcode ("push","dpx1");
599         } else if (_G.dptrInUse ) {
600             emitcode ("push","dpl");
601             emitcode ("push","dph");
602             emitcode ("push","dpx");
603         }
604       /* It's on the 10 bit stack, which is located in
605        * far data space.
606        */
607         if (stack_val < 0 && stack_val > -5) { /* between -5 & -1 */
608             if (useDP2) {
609                 if (options.model == MODEL_FLAT24)
610                 {
611                     emitcode ("mov", "dpx1,#!constbyte",
612                               (options.stack_loc >> 16) & 0xff);
613                 }
614                 emitcode ("mov", "dph1,_bpx+1");
615
616                 emitcode ("mov", "dpl1,_bpx");
617                 emitcode ("mov","dps,#1");
618             } else {
619                 if (options.model == MODEL_FLAT24)
620                 {
621                     emitcode ("mov", "dpx,#!constbyte",
622                               (options.stack_loc >> 16) & 0xff);
623                 }
624                 emitcode ("mov", "dph,_bpx+1");
625                 emitcode ("mov", "dpl,_bpx");
626             }
627             stack_val = -stack_val;
628             while (stack_val--) {
629                 emitcode ("inc","dptr");
630             }
631             if (useDP2) {
632                 emitcode("mov","dps,#0");
633             }
634         }  else {
635             if (_G.accInUse || accuse)
636                 emitcode ("push", "acc");
637
638             if (_G.bInUse || (accuse>1))
639                 emitcode ("push", "b");
640
641             emitcode ("mov", "a,_bpx");
642             emitcode ("clr","c");
643             emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
644             emitcode ("mov","b,a");
645             emitcode ("mov","a,_bpx+1");
646             emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
647             if (useDP2) {
648                 if (options.model == MODEL_FLAT24)
649                 {
650                     emitcode ("mov", "dpx1,#!constbyte",
651                               (options.stack_loc >> 16) & 0xff);
652                 }
653                 emitcode ("mov", "dph1,a");
654                 emitcode ("mov", "dpl1,b");
655             } else {
656                 if (options.model == MODEL_FLAT24)
657                 {
658                     emitcode ("mov", "dpx,#!constbyte",
659                               (options.stack_loc >> 16) & 0xff);
660                 }
661                 emitcode ("mov", "dph,a");
662                 emitcode ("mov", "dpl,b");
663             }
664
665             if (_G.bInUse || (accuse>1))
666                 emitcode ("pop", "b");
667
668             if (_G.accInUse || accuse)
669                 emitcode ("pop", "acc");
670         }
671         sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
672         aop->size = getSize (sym->type);
673         return aop;
674     }
675
676   /* if in bit space */
677   if (IN_BITSPACE (space))
678     {
679       sym->aop = aop = newAsmop (AOP_CRY);
680       aop->aopu.aop_dir = sym->rname;
681       aop->size = getSize (sym->type);
682       return aop;
683     }
684   /* if it is in direct space */
685   if (IN_DIRSPACE (space))
686     {
687       sym->aop = aop = newAsmop (AOP_DIR);
688       aop->aopu.aop_dir = sym->rname;
689       aop->size = getSize (sym->type);
690       return aop;
691     }
692
693   /* special case for a function */
694   if (IS_FUNC (sym->type) && !(sym->isitmp))
695     {
696       sym->aop = aop = newAsmop (AOP_IMMD);
697       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
698       aop->size = FPTRSIZE;
699       return aop;
700     }
701
702   /* only remaining is far space */
703   /* in which case DPTR gets the address */
704   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
705   if (useDP2)
706     {
707       genSetDPTR (1);
708       _flushLazyDPS ();
709       emitcode ("mov", "dptr,#%s", sym->rname);
710       genSetDPTR (0);
711     }
712   else
713     {
714       emitcode ("mov", "dptr,#%s", sym->rname);
715     }
716   aop->size = getSize (sym->type);
717
718   /* if it is in code space */
719   if (IN_CODESPACE (space))
720     aop->code = 1;
721
722   return aop;
723 }
724
725 /*-----------------------------------------------------------------*/
726 /* aopForRemat - rematerialzes an object                           */
727 /*-----------------------------------------------------------------*/
728 static asmop *
729 aopForRemat (symbol * sym)
730 {
731   iCode *ic = sym->rematiCode;
732   asmop *aop = newAsmop (AOP_IMMD);
733   int ptr_type =0;
734   int val = 0;
735
736   for (;;)
737     {
738       if (ic->op == '+')
739         val += (int) operandLitValue (IC_RIGHT (ic));
740       else if (ic->op == '-')
741         val -= (int) operandLitValue (IC_RIGHT (ic));
742       else if (IS_CAST_ICODE(ic)) {
743               sym_link *from_type = operandType(IC_RIGHT(ic));
744               aop->aopu.aop_immd.from_cast_remat = 1;
745               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
746               ptr_type = DCL_TYPE(from_type);
747               if (ptr_type == IPOINTER) {
748                 // bug #481053
749                 ptr_type = POINTER;
750               }
751               continue ;
752       } else break;
753
754       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
755     }
756
757   if (val)
758   {
759       SNPRINTF (buffer, sizeof(buffer),
760                 "(%s %c 0x%04x)",
761                 OP_SYMBOL (IC_LEFT (ic))->rname,
762                 val >= 0 ? '+' : '-',
763                 abs (val) & 0xffffff);
764   }
765   else
766   {
767       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
768       {
769           SNPRINTF(buffer, sizeof(buffer),
770                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
771       }
772       else
773       {
774           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
775       }
776   }
777
778   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
779   /* set immd2 field if required */
780   if (aop->aopu.aop_immd.from_cast_remat)
781   {
782       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
783       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
784   }
785
786   return aop;
787 }
788
789 /*-----------------------------------------------------------------*/
790 /* aopHasRegs - returns true if aop has regs between from-to       */
791 /*-----------------------------------------------------------------*/
792 static int aopHasRegs(asmop *aop, int from, int to)
793 {
794     int size =0;
795
796     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
797
798     for (; size < aop->size ; size++) {
799         int reg;
800         for (reg = from ; reg <= to ; reg++)
801             if (aop->aopu.aop_reg[size] == ds390_regWithIdx(reg)) return 1;
802     }
803     return 0;
804 }
805
806 /*-----------------------------------------------------------------*/
807 /* regsInCommon - two operands have some registers in common       */
808 /*-----------------------------------------------------------------*/
809 static bool
810 regsInCommon (operand * op1, operand * op2)
811 {
812   symbol *sym1, *sym2;
813   int i;
814
815   /* if they have registers in common */
816   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
817     return FALSE;
818
819   sym1 = OP_SYMBOL (op1);
820   sym2 = OP_SYMBOL (op2);
821
822   if (sym1->nRegs == 0 || sym2->nRegs == 0)
823     return FALSE;
824
825   for (i = 0; i < sym1->nRegs; i++)
826     {
827       int j;
828       if (!sym1->regs[i])
829         continue;
830
831       for (j = 0; j < sym2->nRegs; j++)
832         {
833           if (!sym2->regs[j])
834             continue;
835
836           if (sym2->regs[j] == sym1->regs[i])
837             return TRUE;
838         }
839     }
840
841   return FALSE;
842 }
843
844 /*-----------------------------------------------------------------*/
845 /* operandsEqu - equivalent                                        */
846 /*-----------------------------------------------------------------*/
847 static bool
848 operandsEqu (operand * op1, operand * op2)
849 {
850   symbol *sym1, *sym2;
851
852   /* if they not symbols */
853   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
854     return FALSE;
855
856   sym1 = OP_SYMBOL (op1);
857   sym2 = OP_SYMBOL (op2);
858
859   /* if both are itemps & one is spilt
860      and the other is not then false */
861   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
862       sym1->isspilt != sym2->isspilt)
863     return FALSE;
864
865   /* if they are the same */
866   if (sym1 == sym2)
867     return TRUE;
868
869   if (sym1->rname[0] && sym2->rname[0]
870       && strcmp (sym1->rname, sym2->rname) == 0)
871     return TRUE;
872
873
874   /* if left is a tmp & right is not */
875   if (IS_ITEMP (op1) &&
876       !IS_ITEMP (op2) &&
877       sym1->isspilt &&
878       (sym1->usl.spillLoc == sym2))
879     return TRUE;
880
881   if (IS_ITEMP (op2) &&
882       !IS_ITEMP (op1) &&
883       sym2->isspilt &&
884       sym1->level > 0 &&
885       (sym2->usl.spillLoc == sym1))
886     return TRUE;
887
888   /* are they spilt to the same location */
889   if (IS_ITEMP (op2) &&
890       IS_ITEMP (op1) &&
891       sym2->isspilt &&
892       sym1->isspilt &&
893       (sym1->usl.spillLoc == sym2->usl.spillLoc))
894     return TRUE;
895
896   return FALSE;
897 }
898
899 /*-----------------------------------------------------------------*/
900 /* sameRegs - two asmops have the same registers                   */
901 /*-----------------------------------------------------------------*/
902 static bool
903 sameRegs (asmop * aop1, asmop * aop2)
904 {
905   int i;
906
907   if (aop1 == aop2)
908     {
909       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
910         {
911           return FALSE;
912         }
913       return TRUE;
914     }
915
916   if (aop1->type != AOP_REG ||
917       aop2->type != AOP_REG)
918     return FALSE;
919
920   if (aop1->size != aop2->size)
921     return FALSE;
922
923   for (i = 0; i < aop1->size; i++)
924     if (aop1->aopu.aop_reg[i] !=
925         aop2->aopu.aop_reg[i])
926       return FALSE;
927
928   return TRUE;
929 }
930
931 /*-----------------------------------------------------------------*/
932 /* aopOp - allocates an asmop for an operand  :                    */
933 /*-----------------------------------------------------------------*/
934 static void
935 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
936 {
937   asmop *aop;
938   symbol *sym;
939   int i;
940
941   if (!op)
942     return;
943
944   /* if this a literal */
945   if (IS_OP_LITERAL (op))
946     {
947       op->aop = aop = newAsmop (AOP_LIT);
948       aop->aopu.aop_lit = op->operand.valOperand;
949       aop->size = getSize (operandType (op));
950       return;
951     }
952
953   /* if already has a asmop then continue */
954   if (op->aop)
955     {
956       if ((op->aop->type == AOP_DPTR && useDP2)
957           || (op->aop->type == AOP_DPTR2 && !useDP2))
958         op->aop = NULL;
959       else
960         return;
961     }
962
963   /* if the underlying symbol has a aop */
964   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
965     {
966       op->aop = OP_SYMBOL (op)->aop;
967       if ((op->aop->type == AOP_DPTR && useDP2)
968           || (op->aop->type == AOP_DPTR2 && !useDP2))
969         op->aop = NULL;
970       else
971         return;
972     }
973
974   /* if this is a true symbol */
975   if (IS_TRUE_SYMOP (op))
976     {
977       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
978       return;
979     }
980
981   /* this is a temporary : this has
982      only four choices :
983      a) register
984      b) spillocation
985      c) rematerialize
986      d) conditional
987      e) can be a return use only */
988
989   sym = OP_SYMBOL (op);
990
991
992   /* if the type is a conditional */
993   if (sym->regType == REG_CND)
994     {
995       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
996       aop->size = 0;
997       return;
998     }
999
1000   /* if it is spilt then two situations
1001      a) is rematerialize
1002      b) has a spill location */
1003   if (sym->isspilt || sym->nRegs == 0)
1004     {
1005
1006       /* rematerialize it NOW */
1007       if (sym->remat)
1008         {
1009           sym->aop = op->aop = aop =
1010             aopForRemat (sym);
1011           aop->size = getSize (sym->type);
1012           return;
1013         }
1014
1015       if (sym->accuse)
1016         {
1017           int i;
1018           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1019           aop->size = getSize (sym->type);
1020           for (i = 0; i < 2; i++)
1021             aop->aopu.aop_str[i] = accUse[i];
1022           return;
1023         }
1024
1025       if (sym->ruonly)
1026         {
1027           int i;
1028
1029           if (useDP2)
1030             {
1031               /* a AOP_STR uses DPTR, but DPTR is already in use;
1032                * we're just hosed.
1033                */
1034                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1035             }
1036
1037           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1038           aop->size = getSize (sym->type);
1039           for (i = 0; i < fReturnSizeDS390; i++)
1040             aop->aopu.aop_str[i] = fReturn[i];
1041           return;
1042         }
1043
1044       if (sym->dptr) { /* has been allocated to a DPTRn */
1045           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1046           aop->size = getSize (sym->type);
1047           aop->aopu.dptr = sym->dptr;
1048           return ;
1049       }
1050
1051       if (sym->usl.spillLoc)
1052         {
1053           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1054             {
1055               /* force a new aop if sizes differ */
1056               sym->usl.spillLoc->aop = NULL;
1057             }
1058           sym->aop = op->aop = aop =
1059                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1060           aop->size = getSize (sym->type);
1061           return;
1062         }
1063
1064       /* else must be a dummy iTemp */
1065       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1066       aop->size = getSize (sym->type);
1067       return;
1068     }
1069
1070   /* must be in a register */
1071   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1072   aop->size = sym->nRegs;
1073   for (i = 0; i < sym->nRegs; i++)
1074     aop->aopu.aop_reg[i] = sym->regs[i];
1075 }
1076
1077 /*-----------------------------------------------------------------*/
1078 /* freeAsmop - free up the asmop given to an operand               */
1079 /*----------------------------------------------------------------*/
1080 static void
1081 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1082 {
1083   asmop *aop;
1084
1085   if (!op)
1086     aop = aaop;
1087   else
1088     aop = op->aop;
1089
1090   if (!aop)
1091     return;
1092
1093   if (aop->freed)
1094     goto dealloc;
1095
1096   aop->freed = 1;
1097
1098   /* depending on the asmop type only three cases need work AOP_RO
1099      , AOP_R1 && AOP_STK */
1100   switch (aop->type)
1101     {
1102     case AOP_R0:
1103       if (_G.r0Pushed)
1104         {
1105           if (pop)
1106             {
1107               emitcode ("pop", "ar0");
1108               _G.r0Pushed--;
1109             }
1110         }
1111       bitVectUnSetBit (ic->rUsed, R0_IDX);
1112       break;
1113
1114     case AOP_R1:
1115       if (_G.r1Pushed)
1116         {
1117           if (pop)
1118             {
1119               emitcode ("pop", "ar1");
1120               _G.r1Pushed--;
1121             }
1122         }
1123       bitVectUnSetBit (ic->rUsed, R1_IDX);
1124       break;
1125
1126     case AOP_STK:
1127       {
1128         int sz = aop->size;
1129         int stk = aop->aopu.aop_stk + aop->size;
1130         bitVectUnSetBit (ic->rUsed, R0_IDX);
1131         bitVectUnSetBit (ic->rUsed, R1_IDX);
1132
1133         getFreePtr (ic, &aop, FALSE);
1134
1135         if (options.stack10bit)
1136           {
1137             /* I'm not sure what to do here yet... */
1138             /* #STUB */
1139             fprintf (stderr,
1140                      "*** Warning: probably generating bad code for "
1141                      "10 bit stack mode.\n");
1142           }
1143
1144         if (stk)
1145           {
1146             emitcode ("mov", "a,_bp");
1147             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1148             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1149           }
1150         else
1151           {
1152             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1153           }
1154
1155         while (sz--)
1156           {
1157             emitcode ("pop", "acc");
1158             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1159             if (!sz)
1160               break;
1161             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1162           }
1163         op->aop = aop;
1164         freeAsmop (op, NULL, ic, TRUE);
1165         if (_G.r0Pushed)
1166           {
1167             emitcode ("pop", "ar0");
1168             _G.r0Pushed--;
1169           }
1170
1171         if (_G.r1Pushed)
1172           {
1173             emitcode ("pop", "ar1");
1174             _G.r1Pushed--;
1175           }
1176       }
1177     case AOP_DPTR2:
1178         if (_G.dptr1InUse) {
1179             emitcode ("pop","dpx1");
1180             emitcode ("pop","dph1");
1181             emitcode ("pop","dpl1");
1182         }
1183         break;
1184     case AOP_DPTR:
1185         if (_G.dptrInUse) {
1186             emitcode ("pop","dpx");
1187             emitcode ("pop","dph");
1188             emitcode ("pop","dpl");
1189         }
1190         break;
1191     }
1192 dealloc:
1193   /* all other cases just dealloc */
1194   if (op)
1195     {
1196       op->aop = NULL;
1197       if (IS_SYMOP (op))
1198         {
1199           OP_SYMBOL (op)->aop = NULL;
1200           /* if the symbol has a spill */
1201           if (SPIL_LOC (op))
1202             SPIL_LOC (op)->aop = NULL;
1203         }
1204     }
1205 }
1206
1207 #define DEFAULT_ACC_WARNING 0
1208 static int saveAccWarn = DEFAULT_ACC_WARNING;
1209
1210 /*-------------------------------------------------------------------*/
1211 /* aopGet - for fetching value of the aop                            */
1212 /*                                                                   */
1213 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1214 /* in the accumulator. Set it to the name of a free register         */
1215 /* if acc must be preserved; the register will be used to preserve   */
1216 /* acc temporarily and to return the result byte.                    */
1217 /*-------------------------------------------------------------------*/
1218
1219 static char *
1220 aopGet (asmop *aop,
1221         int   offset,
1222         bool  bit16,
1223         bool  dname,
1224         char  *saveAcc)
1225 {
1226   /* offset is greater than
1227      size then zero */
1228   if (offset > (aop->size - 1) &&
1229       aop->type != AOP_LIT)
1230     return zero;
1231
1232   /* depending on type */
1233   switch (aop->type)
1234     {
1235     case AOP_DUMMY:
1236       return zero;
1237
1238     case AOP_R0:
1239     case AOP_R1:
1240       /* if we need to increment it */
1241       while (offset > aop->coff)
1242         {
1243           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1244           aop->coff++;
1245         }
1246
1247       while (offset < aop->coff)
1248         {
1249           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1250           aop->coff--;
1251         }
1252
1253       aop->coff = offset;
1254       if (aop->paged)
1255         {
1256           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1257           return (dname ? "acc" : "a");
1258         }
1259       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1260       return Safe_strdup(buffer);
1261
1262     case AOP_DPTRn:
1263         assert(offset <= 3);
1264         return dptrn[aop->aopu.dptr][offset];
1265
1266     case AOP_DPTR:
1267     case AOP_DPTR2:
1268
1269       if (aop->type == AOP_DPTR2)
1270         {
1271           genSetDPTR (1);
1272         }
1273
1274       if (saveAcc)
1275         {
1276             TR_AP("#1");
1277 //          if (aop->type != AOP_DPTR2)
1278 //          {
1279 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1280 //              emitcode(";", "spanky: saveAcc for DPTR");
1281 //          }
1282
1283             emitcode ("xch", "a, %s", saveAcc);
1284         }
1285
1286       _flushLazyDPS ();
1287
1288       while (offset > aop->coff)
1289         {
1290           emitcode ("inc", "dptr");
1291           aop->coff++;
1292         }
1293
1294       while (offset < aop->coff)
1295         {
1296           emitcode ("lcall", "__decdptr");
1297           aop->coff--;
1298         }
1299
1300       aop->coff = offset;
1301       if (aop->code)
1302         {
1303           emitcode ("clr", "a");
1304           emitcode ("movc", "a,@a+dptr");
1305         }
1306       else
1307         {
1308           emitcode ("movx", "a,@dptr");
1309         }
1310
1311       if (aop->type == AOP_DPTR2)
1312         {
1313           genSetDPTR (0);
1314         }
1315
1316         if (saveAcc)
1317         {
1318        TR_AP("#2");
1319               emitcode ("xch", "a, %s", saveAcc);
1320 //            if (strcmp(saveAcc, "_ap"))
1321 //            {
1322 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1323 //            }
1324
1325               return saveAcc;
1326         }
1327       return (dname ? "acc" : "a");
1328
1329     case AOP_IMMD:
1330       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1331       {
1332           SNPRINTF(buffer, sizeof(buffer),
1333                    "%s",aop->aopu.aop_immd.aop_immd2);
1334       }
1335       else if (bit16)
1336       {
1337          SNPRINTF(buffer, sizeof(buffer),
1338                   "#%s", aop->aopu.aop_immd.aop_immd1);
1339       }
1340       else if (offset)
1341       {
1342           switch (offset) {
1343           case 1:
1344               tsprintf(buffer, sizeof(buffer),
1345                        "#!his",aop->aopu.aop_immd.aop_immd1);
1346               break;
1347           case 2:
1348               tsprintf(buffer, sizeof(buffer),
1349                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1350               break;
1351           case 3:
1352               tsprintf(buffer, sizeof(buffer),
1353                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1354               break;
1355           default: /* should not need this (just in case) */
1356               SNPRINTF (buffer, sizeof(buffer),
1357                         "#(%s >> %d)",
1358                        aop->aopu.aop_immd.aop_immd1,
1359                        offset * 8);
1360           }
1361       }
1362       else
1363       {
1364         SNPRINTF (buffer, sizeof(buffer),
1365                   "#%s", aop->aopu.aop_immd.aop_immd1);
1366       }
1367       return Safe_strdup(buffer);
1368
1369     case AOP_DIR:
1370       if (offset)
1371       {
1372         SNPRINTF (buffer, sizeof(buffer),
1373                   "(%s + %d)",
1374                  aop->aopu.aop_dir,
1375                  offset);
1376       }
1377       else
1378       {
1379         SNPRINTF(buffer, sizeof(buffer),
1380                  "%s", aop->aopu.aop_dir);
1381       }
1382
1383       return Safe_strdup(buffer);
1384
1385     case AOP_REG:
1386       if (dname)
1387         return aop->aopu.aop_reg[offset]->dname;
1388       else
1389         return aop->aopu.aop_reg[offset]->name;
1390
1391     case AOP_CRY:
1392       emitcode ("clr", "a");
1393       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1394       emitcode ("rlc", "a");
1395       return (dname ? "acc" : "a");
1396
1397     case AOP_ACC:
1398       if (!offset && dname)
1399         return "acc";
1400       return aop->aopu.aop_str[offset];
1401
1402     case AOP_LIT:
1403       return aopLiteral (aop->aopu.aop_lit, offset);
1404
1405     case AOP_STR:
1406       aop->coff = offset;
1407       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1408           dname)
1409         return "acc";
1410
1411       return aop->aopu.aop_str[offset];
1412
1413     }
1414
1415   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1416           "aopget got unsupported aop->type");
1417   exit (1);
1418
1419   return NULL;  // not reached, but makes compiler happy.
1420 }
1421 /*-----------------------------------------------------------------*/
1422 /* aopPut - puts a string for a aop                                */
1423 /*-----------------------------------------------------------------*/
1424 static void
1425 aopPut (asmop * aop, char *s, int offset)
1426 {
1427   if (aop->size && offset > (aop->size - 1))
1428     {
1429       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1430               "aopPut got offset > aop->size");
1431       exit (1);
1432     }
1433
1434   /* will assign value to value */
1435   /* depending on where it is ofcourse */
1436   switch (aop->type)
1437     {
1438     case AOP_DUMMY:
1439       MOVA (s);         /* read s in case it was volatile */
1440       break;
1441
1442     case AOP_DIR:
1443         if (offset)
1444         {
1445             SNPRINTF (buffer, sizeof(buffer),
1446                       "(%s + %d)",
1447                       aop->aopu.aop_dir, offset);
1448         }
1449         else
1450         {
1451             SNPRINTF (buffer, sizeof(buffer),
1452                      "%s", aop->aopu.aop_dir);
1453         }
1454
1455
1456         if (strcmp (buffer, s))
1457         {
1458             emitcode ("mov", "%s,%s", buffer, s);
1459         }
1460       break;
1461
1462     case AOP_REG:
1463       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1464           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1465         {
1466           if (*s == '@' ||
1467               strcmp (s, "r0") == 0 ||
1468               strcmp (s, "r1") == 0 ||
1469               strcmp (s, "r2") == 0 ||
1470               strcmp (s, "r3") == 0 ||
1471               strcmp (s, "r4") == 0 ||
1472               strcmp (s, "r5") == 0 ||
1473               strcmp (s, "r6") == 0 ||
1474               strcmp (s, "r7") == 0)
1475             {
1476                 emitcode ("mov", "%s,%s",
1477                           aop->aopu.aop_reg[offset]->dname, s);
1478             }
1479             else
1480             {
1481                 emitcode ("mov", "%s,%s",
1482                           aop->aopu.aop_reg[offset]->name, s);
1483             }
1484         }
1485       break;
1486
1487     case AOP_DPTRn:
1488         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1489         break;
1490
1491     case AOP_DPTR:
1492     case AOP_DPTR2:
1493
1494       if (aop->type == AOP_DPTR2)
1495         {
1496           genSetDPTR (1);
1497         }
1498       _flushLazyDPS ();
1499
1500       if (aop->code)
1501         {
1502           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1503                   "aopPut writting to code space");
1504           exit (1);
1505         }
1506
1507       while (offset > aop->coff)
1508         {
1509           aop->coff++;
1510           emitcode ("inc", "dptr");
1511         }
1512
1513       while (offset < aop->coff)
1514         {
1515           aop->coff--;
1516           emitcode ("lcall", "__decdptr");
1517         }
1518
1519       aop->coff = offset;
1520
1521       /* if not in accumulater */
1522       MOVA (s);
1523
1524       emitcode ("movx", "@dptr,a");
1525
1526       if (aop->type == AOP_DPTR2)
1527         {
1528           genSetDPTR (0);
1529         }
1530       break;
1531
1532     case AOP_R0:
1533     case AOP_R1:
1534       while (offset > aop->coff)
1535         {
1536           aop->coff++;
1537           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1538         }
1539       while (offset < aop->coff)
1540         {
1541           aop->coff--;
1542           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1543         }
1544       aop->coff = offset;
1545
1546       if (aop->paged)
1547         {
1548           MOVA (s);
1549           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1550
1551         }
1552       else if (*s == '@')
1553         {
1554           MOVA (s);
1555           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1556         }
1557       else if (strcmp (s, "r0") == 0 ||
1558                strcmp (s, "r1") == 0 ||
1559                strcmp (s, "r2") == 0 ||
1560                strcmp (s, "r3") == 0 ||
1561                strcmp (s, "r4") == 0 ||
1562                strcmp (s, "r5") == 0 ||
1563                strcmp (s, "r6") == 0 ||
1564                strcmp (s, "r7") == 0)
1565         {
1566           char buff[10];
1567           SNPRINTF(buff, sizeof(buff),
1568                    "a%s", s);
1569           emitcode ("mov", "@%s,%s",
1570                     aop->aopu.aop_ptr->name, buff);
1571         }
1572         else
1573         {
1574             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1575         }
1576       break;
1577
1578     case AOP_STK:
1579       if (strcmp (s, "a") == 0)
1580         emitcode ("push", "acc");
1581       else
1582         if (*s=='@') {
1583           MOVA(s);
1584           emitcode ("push", "acc");
1585         } else {
1586           emitcode ("push", s);
1587         }
1588
1589       break;
1590
1591     case AOP_CRY:
1592       /* if bit variable */
1593       if (!aop->aopu.aop_dir)
1594         {
1595           emitcode ("clr", "a");
1596           emitcode ("rlc", "a");
1597         }
1598       else
1599         {
1600           if (s == zero)
1601             emitcode ("clr", "%s", aop->aopu.aop_dir);
1602           else if (s == one)
1603             emitcode ("setb", "%s", aop->aopu.aop_dir);
1604           else if (!strcmp (s, "c"))
1605             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1606           else
1607             {
1608               if (strcmp (s, "a"))
1609                 {
1610                   MOVA (s);
1611                 }
1612               {
1613                 /* set C, if a >= 1 */
1614                 emitcode ("add", "a,#!constbyte",0xff);
1615                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1616               }
1617             }
1618         }
1619       break;
1620
1621     case AOP_STR:
1622       aop->coff = offset;
1623       if (strcmp (aop->aopu.aop_str[offset], s))
1624         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1625       break;
1626
1627     case AOP_ACC:
1628       aop->coff = offset;
1629       if (!offset && (strcmp (s, "acc") == 0))
1630         break;
1631
1632       if (strcmp (aop->aopu.aop_str[offset], s))
1633         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1634       break;
1635
1636     default:
1637       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1638               "aopPut got unsupported aop->type");
1639       exit (1);
1640     }
1641
1642 }
1643
1644
1645 /*--------------------------------------------------------------------*/
1646 /* reAdjustPreg - points a register back to where it should (coff==0) */
1647 /*--------------------------------------------------------------------*/
1648 static void
1649 reAdjustPreg (asmop * aop)
1650 {
1651   if ((aop->coff==0) || (aop->size <= 1)) {
1652     return;
1653   }
1654
1655   switch (aop->type)
1656     {
1657     case AOP_R0:
1658     case AOP_R1:
1659       while (aop->coff--)
1660         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1661       break;
1662     case AOP_DPTR:
1663     case AOP_DPTR2:
1664       if (aop->type == AOP_DPTR2)
1665         {
1666           genSetDPTR (1);
1667           _flushLazyDPS ();
1668         }
1669       while (aop->coff--)
1670         {
1671           emitcode ("lcall", "__decdptr");
1672         }
1673
1674       if (aop->type == AOP_DPTR2)
1675         {
1676           genSetDPTR (0);
1677         }
1678       break;
1679
1680     }
1681   aop->coff=0;
1682 }
1683
1684 #define AOP(op) op->aop
1685 #define AOP_TYPE(op) AOP(op)->type
1686 #define AOP_SIZE(op) AOP(op)->size
1687 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1688                        AOP_TYPE(x) == AOP_R0))
1689
1690 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1691                         AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
1692                          AOP(x)->paged))
1693
1694 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1695                       (x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
1696                       x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
1697 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
1698 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
1699 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
1700
1701 // The following two macros can be used even if the aop has not yet been aopOp'd.
1702 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
1703 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
1704
1705 /* Workaround for DS80C390 bug: div ab may return bogus results
1706  * if A is accessed in instruction immediately before the div.
1707  *
1708  * Will be fixed in B4 rev of processor, Dallas claims.
1709  */
1710
1711 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
1712     if (!AOP_NEEDSACC(RIGHT))         \
1713     {               \
1714       /* We can load A first, then B, since     \
1715        * B (the RIGHT operand) won't clobber A,   \
1716        * thus avoiding touching A right before the div. \
1717        */             \
1718       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
1719       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);     \
1720       MOVA(L);            \
1721       L = aopGet(AOP(RIGHT),0,FALSE,FALSE,"b"); \
1722       MOVB(L); \
1723     }               \
1724     else              \
1725     {               \
1726       /* Just stuff in a nop after loading A. */    \
1727       emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,NULL));\
1728       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);   \
1729       MOVA(L);            \
1730       emitcode("nop", "; workaround for DS80C390 div bug.");  \
1731     }
1732
1733
1734 /*-----------------------------------------------------------------*/
1735 /* opIsGptr: returns non-zero if the passed operand is       */
1736 /* a generic pointer type.             */
1737 /*-----------------------------------------------------------------*/
1738 static int
1739 opIsGptr (operand * op)
1740 {
1741   sym_link *type = operandType (op);
1742
1743   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1744     {
1745       return 1;
1746     }
1747   return 0;
1748 }
1749
1750 /*-----------------------------------------------------------------*/
1751 /* getDataSize - get the operand data size                         */
1752 /*-----------------------------------------------------------------*/
1753 static int
1754 getDataSize (operand * op)
1755 {
1756   int size;
1757   size = AOP_SIZE (op);
1758   if (size == GPTRSIZE)
1759     {
1760       sym_link *type = operandType (op);
1761       if (IS_GENPTR (type))
1762         {
1763           /* generic pointer; arithmetic operations
1764            * should ignore the high byte (pointer type).
1765            */
1766           size--;
1767         }
1768     }
1769   return size;
1770 }
1771
1772 /*-----------------------------------------------------------------*/
1773 /* outAcc - output Acc                                             */
1774 /*-----------------------------------------------------------------*/
1775 static void
1776 outAcc (operand * result)
1777 {
1778   int size, offset;
1779   size = getDataSize (result);
1780   if (size)
1781     {
1782       aopPut (AOP (result), "a", 0);
1783       size--;
1784       offset = 1;
1785       /* unsigned or positive */
1786       while (size--)
1787         {
1788           aopPut (AOP (result), zero, offset++);
1789         }
1790     }
1791 }
1792
1793 /*-----------------------------------------------------------------*/
1794 /* outBitC - output a bit C                                        */
1795 /*-----------------------------------------------------------------*/
1796 static void
1797 outBitC (operand * result)
1798 {
1799   /* if the result is bit */
1800   if (AOP_TYPE (result) == AOP_CRY)
1801     {
1802       aopPut (AOP (result), "c", 0);
1803     }
1804   else
1805     {
1806       emitcode ("clr", "a");
1807       emitcode ("rlc", "a");
1808       outAcc (result);
1809     }
1810 }
1811
1812 /*-----------------------------------------------------------------*/
1813 /* toBoolean - emit code for orl a,operator(sizeop)                */
1814 /*-----------------------------------------------------------------*/
1815 static void
1816 toBoolean (operand * oper)
1817 {
1818   int   size = AOP_SIZE (oper) - 1;
1819   int   offset = 1;
1820   bool usedB = FALSE;
1821
1822   /* The generic part of a generic pointer should
1823    * not participate in it's truth value.
1824    *
1825    * i.e. 0x10000000 is zero.
1826    */
1827   if (opIsGptr (oper))
1828     {
1829       D (emitcode (";", "toBoolean: generic ptr special case."););
1830       size--;
1831     }
1832
1833   _startLazyDPSEvaluation ();
1834   if (AOP_NEEDSACC (oper) && size)
1835     {
1836       usedB = TRUE;
1837       if (_G.bInUse)
1838       {
1839           emitcode ("push", "b");
1840       }
1841       MOVB (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1842     }
1843   else
1844     {
1845       MOVA (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1846     }
1847
1848   while (size--)
1849     {
1850       if (usedB)
1851         {
1852           emitcode ("orl", "b,%s",
1853                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1854         }
1855       else
1856         {
1857           emitcode ("orl", "a,%s",
1858                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1859         }
1860     }
1861   _endLazyDPSEvaluation ();
1862
1863   if (usedB)
1864     {
1865       emitcode ("mov", "a,b");
1866       if (_G.bInUse)
1867       {
1868           emitcode ("pop", "b");
1869       }
1870
1871     }
1872 }
1873
1874
1875 /*-----------------------------------------------------------------*/
1876 /* genNot - generate code for ! operation                          */
1877 /*-----------------------------------------------------------------*/
1878 static void
1879 genNot (iCode * ic)
1880 {
1881   symbol *tlbl;
1882
1883   D (emitcode (";", "genNot "););
1884
1885   /* assign asmOps to operand & result */
1886   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1887   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1888
1889   /* if in bit space then a special case */
1890   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1891     {
1892       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1893       emitcode ("cpl", "c");
1894       outBitC (IC_RESULT (ic));
1895       goto release;
1896     }
1897
1898   toBoolean (IC_LEFT (ic));
1899
1900   tlbl = newiTempLabel (NULL);
1901   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
1902   emitcode ("", "!tlabeldef", tlbl->key + 100);
1903   outBitC (IC_RESULT (ic));
1904
1905 release:
1906   /* release the aops */
1907   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1908   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1909 }
1910
1911
1912 /*-----------------------------------------------------------------*/
1913 /* genCpl - generate code for complement                           */
1914 /*-----------------------------------------------------------------*/
1915 static void
1916 genCpl (iCode * ic)
1917 {
1918   int offset = 0;
1919   int size;
1920   symbol *tlbl;
1921
1922   D (emitcode (";", "genCpl "););
1923
1924
1925   /* assign asmOps to operand & result */
1926   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1927   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1928
1929   /* special case if in bit space */
1930   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) {
1931     if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) {
1932       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1933       emitcode ("cpl", "c");
1934       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1935       goto release;
1936     }
1937     tlbl=newiTempLabel(NULL);
1938     emitcode ("cjne", "%s,#0x01,%05d$",
1939               aopGet(AOP(IC_LEFT(ic)), 0, FALSE,FALSE,NULL), tlbl->key+100);
1940     emitcode ("", "%05d$:", tlbl->key+100);
1941     outBitC (IC_RESULT(ic));
1942     goto release;
1943   }
1944
1945   size = AOP_SIZE (IC_RESULT (ic));
1946   _startLazyDPSEvaluation ();
1947   while (size--)
1948     {
1949       MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
1950       emitcode ("cpl", "a");
1951       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1952     }
1953   _endLazyDPSEvaluation ();
1954
1955
1956 release:
1957   /* release the aops */
1958   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1959   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1960 }
1961
1962 /*-----------------------------------------------------------------*/
1963 /* genUminusFloat - unary minus for floating points                */
1964 /*-----------------------------------------------------------------*/
1965 static void
1966 genUminusFloat (operand * op, operand * result)
1967 {
1968   int size, offset = 0;
1969
1970   D(emitcode (";", "genUminusFloat"););
1971
1972   /* for this we just copy and then flip the bit */
1973
1974   _startLazyDPSEvaluation ();
1975   size = AOP_SIZE (op) - 1;
1976
1977   while (size--)
1978   {
1979       aopPut (AOP (result),
1980               aopGet (AOP (op), offset, FALSE, FALSE, NULL),
1981               offset);
1982       offset++;
1983     }
1984
1985   MOVA(aopGet (AOP (op), offset, FALSE, FALSE, NULL));
1986
1987   emitcode ("cpl", "acc.7");
1988   aopPut (AOP (result), "a", offset);
1989   _endLazyDPSEvaluation ();
1990 }
1991
1992 /*-----------------------------------------------------------------*/
1993 /* genUminus - unary minus code generation                         */
1994 /*-----------------------------------------------------------------*/
1995 static void
1996 genUminus (iCode * ic)
1997 {
1998   int offset, size;
1999   sym_link *optype;
2000
2001   D (emitcode (";", "genUminus "););
2002
2003   /* assign asmops */
2004   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2005   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2006
2007   /* if both in bit space then special
2008      case */
2009   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2010       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2011     {
2012
2013       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2014       emitcode ("cpl", "c");
2015       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2016       goto release;
2017     }
2018
2019   optype = operandType (IC_LEFT (ic));
2020
2021   /* if float then do float stuff */
2022   if (IS_FLOAT (optype))
2023     {
2024       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2025       goto release;
2026     }
2027
2028   /* otherwise subtract from zero */
2029   size = AOP_SIZE (IC_LEFT (ic));
2030   offset = 0;
2031   _startLazyDPSEvaluation ();
2032   while (size--)
2033     {
2034       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL);
2035       if (!strcmp (l, "a"))
2036         {
2037           if (offset == 0)
2038             SETC;
2039           emitcode ("cpl", "a");
2040           emitcode ("addc", "a,#0");
2041         }
2042       else
2043         {
2044           if (offset == 0)
2045             CLRC;
2046           emitcode ("clr", "a");
2047           emitcode ("subb", "a,%s", l);
2048         }
2049       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2050     }
2051   _endLazyDPSEvaluation ();
2052
2053   /* if any remaining bytes in the result */
2054   /* we just need to propagate the sign   */
2055   if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic)))) != 0)
2056     {
2057       emitcode ("rlc", "a");
2058       emitcode ("subb", "a,acc");
2059       while (size--)
2060         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2061     }
2062
2063 release:
2064   /* release the aops */
2065   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2066   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2067 }
2068
2069 /*-----------------------------------------------------------------*/
2070 /* savermask - saves registers in the mask                         */
2071 /*-----------------------------------------------------------------*/
2072 static void savermask(bitVect *rs_mask)
2073 {
2074     int i;
2075     if (options.useXstack) {
2076         if (bitVectBitValue (rs_mask, R0_IDX))
2077             emitcode ("mov", "b,r0");
2078         emitcode ("mov", "r0,%s", spname);
2079         for (i = 0; i < ds390_nRegs; i++) {
2080             if (bitVectBitValue (rs_mask, i)) {
2081                 if (i == R0_IDX)
2082                     emitcode ("mov", "a,b");
2083                 else
2084                     emitcode ("mov", "a,%s", ds390_regWithIdx (i)->name);
2085                 emitcode ("movx", "@r0,a");
2086                 emitcode ("inc", "r0");
2087             }
2088         }
2089         emitcode ("mov", "%s,r0", spname);
2090         if (bitVectBitValue (rs_mask, R0_IDX))
2091             emitcode ("mov", "r0,b");
2092     } else {
2093         for (i = 0; i < ds390_nRegs; i++) {
2094             if (bitVectBitValue (rs_mask, i))
2095                 emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
2096         }
2097     }
2098 }
2099
2100 /*-----------------------------------------------------------------*/
2101 /* saveRegisters - will look for a call and save the registers     */
2102 /*-----------------------------------------------------------------*/
2103 static void
2104 saveRegisters (iCode * lic)
2105 {
2106   iCode *ic;
2107   bitVect *rsave;
2108
2109   /* look for call */
2110   for (ic = lic; ic; ic = ic->next)
2111     if (ic->op == CALL || ic->op == PCALL)
2112       break;
2113
2114   if (!ic)
2115     {
2116       fprintf (stderr, "found parameter push with no function call\n");
2117       return;
2118     }
2119
2120   /* if the registers have been saved already then
2121      do nothing */
2122   if (ic->regsSaved
2123       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2124     return ;
2125
2126   /* special case if DPTR alive across a function call then must save it
2127      even though callee saves */
2128   if (IS_SYMOP(IC_LEFT(ic)) &&
2129       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2130       int i;
2131       rsave = newBitVect(ic->rMask->size);
2132       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2133           if (bitVectBitValue(ic->rMask,i))
2134               rsave = bitVectSetBit(rsave,i);
2135       }
2136       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2137   } else {
2138     /* safe the registers in use at this time but skip the
2139        ones for the result */
2140     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2141                            ds390_rUmaskForOp (IC_RESULT(ic)));
2142   }
2143   ic->regsSaved = 1;
2144   savermask(rsave);
2145 }
2146
2147 /*-----------------------------------------------------------------*/
2148 /* usavermask - restore registers with mask                        */
2149 /*-----------------------------------------------------------------*/
2150 static void unsavermask(bitVect *rs_mask)
2151 {
2152     int i;
2153     if (options.useXstack) {
2154         emitcode ("mov", "r0,%s", spname);
2155         for (i = ds390_nRegs; i >= 0; i--) {
2156             if (bitVectBitValue (rs_mask, i)) {
2157                 emitcode ("dec", "r0");
2158                 emitcode ("movx", "a,@r0");
2159                 if (i == R0_IDX)
2160                     emitcode ("mov", "b,a");
2161                 else
2162                     emitcode ("mov", "%s,a", ds390_regWithIdx (i)->name);
2163             }
2164         }
2165         emitcode ("mov", "%s,r0", spname);
2166         if (bitVectBitValue (rs_mask, R0_IDX))
2167             emitcode ("mov", "r0,b");
2168     } else {
2169         for (i = ds390_nRegs; i >= 0; i--) {
2170             if (bitVectBitValue (rs_mask, i))
2171                 emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
2172         }
2173     }
2174 }
2175
2176 /*-----------------------------------------------------------------*/
2177 /* unsaveRegisters - pop the pushed registers                      */
2178 /*-----------------------------------------------------------------*/
2179 static void
2180 unsaveRegisters (iCode * ic)
2181 {
2182   bitVect *rsave;
2183
2184   if (IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2185       int i;
2186       rsave = newBitVect(ic->rMask->size);
2187       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2188           if (bitVectBitValue(ic->rMask,i))
2189               rsave = bitVectSetBit(rsave,i);
2190       }
2191       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2192   } else {
2193     /* restore the registers in use at this time but skip the
2194        ones for the result */
2195     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2196                            ds390_rUmaskForOp (IC_RESULT(ic)));
2197   }
2198   unsavermask(rsave);
2199 }
2200
2201
2202 /*-----------------------------------------------------------------*/
2203 /* pushSide -                */
2204 /*-----------------------------------------------------------------*/
2205 static void
2206 pushSide (operand * oper, int size)
2207 {
2208   int offset = 0;
2209   _startLazyDPSEvaluation ();
2210   while (size--)
2211     {
2212       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE, NULL);
2213       if (AOP_TYPE (oper) != AOP_REG &&
2214           AOP_TYPE (oper) != AOP_DIR &&
2215           strcmp (l, "a"))
2216         {
2217           emitcode ("mov", "a,%s", l);
2218           emitcode ("push", "acc");
2219         }
2220       else
2221         emitcode ("push", "%s", l);
2222     }
2223   _endLazyDPSEvaluation ();
2224 }
2225
2226 /*-----------------------------------------------------------------*/
2227 /* assignResultValue -               */
2228 /*-----------------------------------------------------------------*/
2229 static void
2230 assignResultValue (operand * oper)
2231 {
2232   int offset = 0;
2233   int size = AOP_SIZE (oper);
2234   bool pushedAcc = FALSE;
2235
2236   if (size == fReturnSizeDS390)
2237   {
2238       /* I don't think this case can ever happen... */
2239       /* ACC is the last part of this. If writing the result
2240        * uses AC, we must preserve it.
2241        */
2242       if (AOP_NEEDSACC(oper))
2243       {
2244           emitcode(";", "assignResultValue special case for ACC.");
2245           emitcode("push", "acc");
2246           pushedAcc = TRUE;
2247           size--;
2248       }
2249   }
2250
2251
2252   _startLazyDPSEvaluation ();
2253   while (size--)
2254     {
2255       aopPut (AOP (oper), fReturn[offset], offset);
2256       offset++;
2257     }
2258   _endLazyDPSEvaluation ();
2259
2260   if (pushedAcc)
2261     {
2262         emitcode("pop", "acc");
2263         aopPut(AOP(oper), "a", offset);
2264     }
2265 }
2266
2267
2268 /*-----------------------------------------------------------------*/
2269 /* genXpush - pushes onto the external stack                       */
2270 /*-----------------------------------------------------------------*/
2271 static void
2272 genXpush (iCode * ic)
2273 {
2274   asmop *aop = newAsmop (0);
2275   regs *r;
2276   int size, offset = 0;
2277
2278   D (emitcode (";", "genXpush ");
2279     );
2280
2281   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2282   r = getFreePtr (ic, &aop, FALSE);
2283
2284
2285   emitcode ("mov", "%s,_spx", r->name);
2286
2287   size = AOP_SIZE (IC_LEFT (ic));
2288   _startLazyDPSEvaluation ();
2289   while (size--)
2290     {
2291
2292       MOVA (aopGet (AOP (IC_LEFT (ic)),
2293                         offset++, FALSE, FALSE, NULL));
2294       emitcode ("movx", "@%s,a", r->name);
2295       emitcode ("inc", "%s", r->name);
2296
2297     }
2298   _endLazyDPSEvaluation ();
2299
2300
2301   emitcode ("mov", "_spx,%s", r->name);
2302
2303   freeAsmop (NULL, aop, ic, TRUE);
2304   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2305 }
2306
2307 /*-----------------------------------------------------------------*/
2308 /* genIpush - generate code for pushing this gets a little complex  */
2309 /*-----------------------------------------------------------------*/
2310 static void
2311 genIpush (iCode * ic)
2312 {
2313   int size, offset = 0;
2314   char *l;
2315
2316   D (emitcode (";", "genIpush ");
2317     );
2318
2319   /* if this is not a parm push : ie. it is spill push
2320      and spill push is always done on the local stack */
2321   if (!ic->parmPush)
2322     {
2323
2324       /* and the item is spilt then do nothing */
2325       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2326         return;
2327
2328       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2329       size = AOP_SIZE (IC_LEFT (ic));
2330       /* push it on the stack */
2331       _startLazyDPSEvaluation ();
2332       while (size--)
2333         {
2334           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2335           if (*l == '#')
2336             {
2337               MOVA (l);
2338               l = "acc";
2339             }
2340           emitcode ("push", "%s", l);
2341         }
2342       _endLazyDPSEvaluation ();
2343       return;
2344     }
2345
2346   /* this is a paramter push: in this case we call
2347      the routine to find the call and save those
2348      registers that need to be saved */
2349   saveRegisters (ic);
2350
2351   /* if use external stack then call the external
2352      stack pushing routine */
2353   if (options.useXstack)
2354     {
2355       genXpush (ic);
2356       return;
2357     }
2358
2359   /* then do the push */
2360   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2361
2362   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2363   size = AOP_SIZE (IC_LEFT (ic));
2364
2365   _startLazyDPSEvaluation ();
2366   while (size--)
2367     {
2368       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2369       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2370           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2371           strcmp (l, "acc"))
2372         {
2373           emitcode ("mov", "a,%s", l);
2374           emitcode ("push", "acc");
2375         }
2376       else
2377         {
2378             emitcode ("push", "%s", l);
2379         }
2380     }
2381   _endLazyDPSEvaluation ();
2382
2383   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2384 }
2385
2386 /*-----------------------------------------------------------------*/
2387 /* genIpop - recover the registers: can happen only for spilling   */
2388 /*-----------------------------------------------------------------*/
2389 static void
2390 genIpop (iCode * ic)
2391 {
2392   int size, offset;
2393
2394   D (emitcode (";", "genIpop ");
2395     );
2396
2397
2398   /* if the temp was not pushed then */
2399   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2400     return;
2401
2402   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2403   size = AOP_SIZE (IC_LEFT (ic));
2404   offset = (size - 1);
2405   _startLazyDPSEvaluation ();
2406   while (size--)
2407     {
2408       emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2409                                      FALSE, TRUE, NULL));
2410     }
2411   _endLazyDPSEvaluation ();
2412
2413   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2414 }
2415
2416 /*-----------------------------------------------------------------*/
2417 /* unsaveRBank - restores the resgister bank from stack            */
2418 /*-----------------------------------------------------------------*/
2419 static void
2420 unsaveRBank (int bank, iCode * ic, bool popPsw)
2421 {
2422   int i;
2423   asmop *aop = NULL;
2424   regs *r = NULL;
2425
2426   if (options.useXstack)
2427   {
2428       if (!ic)
2429       {
2430           /* Assume r0 is available for use. */
2431           r = ds390_regWithIdx (R0_IDX);;
2432       }
2433       else
2434       {
2435           aop = newAsmop (0);
2436           r = getFreePtr (ic, &aop, FALSE);
2437       }
2438       emitcode ("mov", "%s,_spx", r->name);
2439   }
2440
2441   if (popPsw)
2442     {
2443       if (options.useXstack)
2444       {
2445           emitcode ("movx", "a,@%s", r->name);
2446           emitcode ("mov", "psw,a");
2447           emitcode ("dec", "%s", r->name);
2448         }
2449       else
2450       {
2451         emitcode ("pop", "psw");
2452       }
2453     }
2454
2455   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2456     {
2457       if (options.useXstack)
2458         {
2459           emitcode ("movx", "a,@%s", r->name);
2460           emitcode ("mov", "(%s+%d),a",
2461                     regs390[i].base, 8 * bank + regs390[i].offset);
2462           emitcode ("dec", "%s", r->name);
2463
2464         }
2465       else
2466         emitcode ("pop", "(%s+%d)",
2467                   regs390[i].base, 8 * bank + regs390[i].offset);
2468     }
2469
2470   if (options.useXstack)
2471     {
2472       emitcode ("mov", "_spx,%s", r->name);
2473     }
2474
2475   if (aop)
2476   {
2477       freeAsmop (NULL, aop, ic, TRUE);
2478   }
2479 }
2480
2481 /*-----------------------------------------------------------------*/
2482 /* saveRBank - saves an entire register bank on the stack          */
2483 /*-----------------------------------------------------------------*/
2484 static void
2485 saveRBank (int bank, iCode * ic, bool pushPsw)
2486 {
2487   int i;
2488   asmop *aop = NULL;
2489   regs *r = NULL;
2490
2491   if (options.useXstack)
2492     {
2493         if (!ic)
2494         {
2495           /* Assume r0 is available for use. */
2496                   r = ds390_regWithIdx (R0_IDX);;
2497         }
2498         else
2499         {
2500           aop = newAsmop (0);
2501           r = getFreePtr (ic, &aop, FALSE);
2502         }
2503         emitcode ("mov", "%s,_spx", r->name);
2504     }
2505
2506   for (i = 0; i < 8 ; i++) /* only R0-R7 needs saving */
2507     {
2508       if (options.useXstack)
2509         {
2510           emitcode ("inc", "%s", r->name);
2511           emitcode ("mov", "a,(%s+%d)",
2512                     regs390[i].base, 8 * bank + regs390[i].offset);
2513           emitcode ("movx", "@%s,a", r->name);
2514         }
2515       else
2516         emitcode ("push", "(%s+%d)",
2517                   regs390[i].base, 8 * bank + regs390[i].offset);
2518     }
2519
2520   if (pushPsw)
2521     {
2522       if (options.useXstack)
2523         {
2524           emitcode ("mov", "a,psw");
2525           emitcode ("movx", "@%s,a", r->name);
2526           emitcode ("inc", "%s", r->name);
2527           emitcode ("mov", "_spx,%s", r->name);
2528         }
2529       else
2530       {
2531         emitcode ("push", "psw");
2532       }
2533
2534       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2535     }
2536
2537   if (aop)
2538   {
2539        freeAsmop (NULL, aop, ic, TRUE);
2540   }
2541
2542   if (ic)
2543   {
2544       ic->bankSaved = 1;
2545   }
2546 }
2547
2548 /*-----------------------------------------------------------------*/
2549 /* genSend - gen code for SEND                                     */
2550 /*-----------------------------------------------------------------*/
2551 static void genSend(set *sendSet)
2552 {
2553     iCode *sic;
2554     int sendCount = 0 ;
2555     static int rb1_count = 0;
2556
2557     for (sic = setFirstItem (sendSet); sic;
2558          sic = setNextItem (sendSet)) {
2559         int size, offset = 0;
2560
2561         size=getSize(operandType(IC_LEFT(sic)));
2562         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2563         if (sendCount == 0) { /* first parameter */
2564             // we know that dpl(hxb) is the result, so
2565             rb1_count = 0 ;
2566             _startLazyDPSEvaluation ();
2567             if (size>1) {
2568                 aopOp (IC_LEFT (sic), sic, FALSE,
2569                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2570             } else {
2571                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2572             }
2573             while (size--) {
2574                 char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2575                                   FALSE, FALSE, NULL);
2576                 if (strcmp (l, fReturn[offset])) {
2577                     emitcode ("mov", "%s,%s",
2578                               fReturn[offset],
2579                               l);
2580                 }
2581                 offset++;
2582             }
2583             _endLazyDPSEvaluation ();
2584             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2585             rb1_count =0;
2586         } else { /* if more parameter in registers */
2587             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2588             while (size--) {
2589                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (AOP (IC_LEFT (sic)), offset++,
2590                                                                 FALSE, FALSE, NULL));
2591             }
2592             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2593         }
2594         sendCount++;
2595     }
2596 }
2597
2598 static void
2599 adjustEsp(const char *reg)
2600 {
2601     emitcode ("anl","%s,#3", reg);
2602     if (TARGET_IS_DS400)
2603     {
2604         emitcode ("orl","%s,#!constbyte",
2605                   reg,
2606                   (options.stack_loc >> 8) & 0xff);
2607     }
2608 }
2609
2610 /*-----------------------------------------------------------------*/
2611 /* genCall - generates a call statement                            */
2612 /*-----------------------------------------------------------------*/
2613 static void
2614 genCall (iCode * ic)
2615 {
2616   sym_link *dtype;
2617   bool restoreBank = FALSE;
2618   bool swapBanks = FALSE;
2619
2620   D (emitcode (";", "genCall "););
2621
2622   /* if we are calling a not _naked function that is not using
2623      the same register bank then we need to save the
2624      destination registers on the stack */
2625   dtype = operandType (IC_LEFT (ic));
2626   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
2627       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2628       IFFUNC_ISISR (currFunc->type))
2629   {
2630       if (!ic->bankSaved)
2631       {
2632            /* This is unexpected; the bank should have been saved in
2633             * genFunction.
2634             */
2635            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2636            restoreBank = TRUE;
2637       }
2638       swapBanks = TRUE;
2639   }
2640
2641     /* if caller saves & we have not saved then */
2642     if (!ic->regsSaved)
2643       saveRegisters (ic);
2644
2645   /* if send set is not empty the assign */
2646   /* We've saved all the registers we care about;
2647   * therefore, we may clobber any register not used
2648   * in the calling convention (i.e. anything not in
2649   * fReturn.
2650   */
2651   if (_G.sendSet)
2652     {
2653         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2654             genSend(reverseSet(_G.sendSet));
2655         } else {
2656             genSend(_G.sendSet);
2657         }
2658       _G.sendSet = NULL;
2659     }
2660
2661   if (swapBanks)
2662   {
2663         emitcode ("mov", "psw,#!constbyte",
2664            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2665   }
2666
2667   /* make the call */
2668   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2669                             OP_SYMBOL (IC_LEFT (ic))->rname :
2670                             OP_SYMBOL (IC_LEFT (ic))->name));
2671
2672   if (swapBanks)
2673   {
2674        emitcode ("mov", "psw,#!constbyte",
2675           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2676   }
2677
2678   /* if we need assign a result value */
2679   if ((IS_ITEMP (IC_RESULT (ic)) &&
2680        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2681         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2682         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2683       IS_TRUE_SYMOP (IC_RESULT (ic)))
2684     {
2685       if (isOperandInFarSpace (IC_RESULT (ic))
2686           && getSize (operandType (IC_RESULT (ic))) <= 2)
2687         {
2688           int size = getSize (operandType (IC_RESULT (ic)));
2689
2690           /* Special case for 1 or 2 byte return in far space. */
2691           MOVA (fReturn[0]);
2692           if (size > 1)
2693             {
2694               emitcode ("mov", "b,%s", fReturn[1]);
2695               _G.bInUse++;
2696             }
2697
2698           _G.accInUse++;
2699           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2700           _G.accInUse--;
2701
2702           if (size > 1)
2703             _G.bInUse--;
2704
2705           aopPut (AOP (IC_RESULT (ic)), "a", 0);
2706
2707           if (size > 1)
2708             {
2709               aopPut (AOP (IC_RESULT (ic)), "b", 1);
2710             }
2711           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2712         }
2713       else
2714         {
2715           _G.bInUse++;
2716           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2717           _G.bInUse--;
2718
2719           assignResultValue (IC_RESULT (ic));
2720
2721           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2722         }
2723     }
2724
2725   /* adjust the stack for parameters if
2726      required */
2727   if (ic->parmBytes) {
2728       int i;
2729       if (options.stack10bit) {
2730           if (ic->parmBytes <= 10) {
2731               emitcode(";","stack adjustment for parms");
2732               for (i=0; i < ic->parmBytes ; i++) {
2733                   emitcode("pop","acc");
2734               }
2735           } else {
2736               PROTECT_SP;
2737               emitcode ("clr","c");
2738               emitcode ("mov","a,sp");
2739               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2740               emitcode ("mov","sp,a");
2741               emitcode ("mov","a,esp");
2742               adjustEsp("a");
2743               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2744               emitcode ("mov","esp,a");
2745               UNPROTECT_SP;
2746           }
2747       } else {
2748           if (ic->parmBytes > 3) {
2749               emitcode ("mov", "a,%s", spname);
2750               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2751               emitcode ("mov", "%s,a", spname);
2752           } else
2753               for (i = 0; i < ic->parmBytes; i++)
2754                   emitcode ("dec", "%s", spname);
2755       }
2756   }
2757
2758   /* if we hade saved some registers then unsave them */
2759   if (ic->regsSaved)
2760     unsaveRegisters (ic);
2761
2762   /* if register bank was saved then pop them */
2763   if (restoreBank)
2764     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2765 }
2766
2767 /*-----------------------------------------------------------------*/
2768 /* genPcall - generates a call by pointer statement                */
2769 /*-----------------------------------------------------------------*/
2770 static void
2771 genPcall (iCode * ic)
2772 {
2773   sym_link *dtype;
2774   symbol *rlbl = newiTempLabel (NULL);
2775   bool restoreBank=FALSE;
2776
2777   D (emitcode (";", "genPcall ");
2778     );
2779
2780
2781   /* if caller saves & we have not saved then */
2782   if (!ic->regsSaved)
2783     saveRegisters (ic);
2784
2785   /* if we are calling a function that is not using
2786      the same register bank then we need to save the
2787      destination registers on the stack */
2788   dtype = operandType (IC_LEFT (ic));
2789   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
2790       IFFUNC_ISISR (currFunc->type) &&
2791       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
2792     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2793     restoreBank=TRUE;
2794   }
2795
2796   /* push the return address on to the stack */
2797   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
2798   emitcode ("push", "acc");
2799   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
2800   emitcode ("push", "acc");
2801
2802   if (options.model == MODEL_FLAT24)
2803     {
2804       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
2805       emitcode ("push", "acc");
2806     }
2807
2808   /* now push the calling address */
2809   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2810
2811   pushSide (IC_LEFT (ic), FPTRSIZE);
2812
2813   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2814
2815   /* if send set is not empty the assign */
2816   if (_G.sendSet)
2817     {
2818         genSend(reverseSet(_G.sendSet));
2819         _G.sendSet = NULL;
2820     }
2821
2822   emitcode ("ret", "");
2823   emitcode ("", "!tlabeldef", (rlbl->key + 100));
2824
2825
2826   /* if we need assign a result value */
2827   if ((IS_ITEMP (IC_RESULT (ic)) &&
2828        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2829         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2830       IS_TRUE_SYMOP (IC_RESULT (ic)))
2831     {
2832
2833       _G.accInUse++;
2834       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2835       _G.accInUse--;
2836
2837       assignResultValue (IC_RESULT (ic));
2838
2839       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2840     }
2841
2842   /* adjust the stack for parameters if
2843      required */
2844   if (ic->parmBytes)
2845     {
2846       int i;
2847       if (options.stack10bit) {
2848           if (ic->parmBytes <= 10) {
2849               emitcode(";","stack adjustment for parms");
2850               for (i=0; i < ic->parmBytes ; i++) {
2851                   emitcode("pop","acc");
2852               }
2853           } else {
2854               PROTECT_SP;
2855               emitcode ("clr","c");
2856               emitcode ("mov","a,sp");
2857               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2858               emitcode ("mov","sp,a");
2859               emitcode ("mov","a,esp");
2860               adjustEsp("a");
2861               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2862               emitcode ("mov","esp,a");
2863               UNPROTECT_SP;
2864           }
2865       } else {
2866           if (ic->parmBytes > 3) {
2867               emitcode ("mov", "a,%s", spname);
2868               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2869               emitcode ("mov", "%s,a", spname);
2870           }
2871           else
2872               for (i = 0; i < ic->parmBytes; i++)
2873                   emitcode ("dec", "%s", spname);
2874
2875       }
2876     }
2877   /* if register bank was saved then unsave them */
2878   if (restoreBank)
2879     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2880
2881   /* if we hade saved some registers then
2882      unsave them */
2883   if (ic->regsSaved)
2884     unsaveRegisters (ic);
2885
2886 }
2887
2888 /*-----------------------------------------------------------------*/
2889 /* resultRemat - result  is rematerializable                       */
2890 /*-----------------------------------------------------------------*/
2891 static int
2892 resultRemat (iCode * ic)
2893 {
2894   if (SKIP_IC (ic) || ic->op == IFX)
2895     return 0;
2896
2897   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2898     {
2899       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2900       if (sym->remat && !POINTER_SET (ic))
2901         return 1;
2902     }
2903
2904   return 0;
2905 }
2906
2907 #if defined(__BORLANDC__) || defined(_MSC_VER)
2908 #define STRCASECMP stricmp
2909 #else
2910 #define STRCASECMP strcasecmp
2911 #endif
2912
2913 /*-----------------------------------------------------------------*/
2914 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2915 /*-----------------------------------------------------------------*/
2916 static int
2917 regsCmp(void *p1, void *p2)
2918 {
2919   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2920 }
2921
2922 static bool
2923 inExcludeList (char *s)
2924 {
2925   const char *p = setFirstItem(options.excludeRegsSet);
2926
2927   if (p == NULL || STRCASECMP(p, "none") == 0)
2928     return FALSE;
2929
2930
2931   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2932 }
2933
2934 /*-----------------------------------------------------------------*/
2935 /* genFunction - generated code for function entry                 */
2936 /*-----------------------------------------------------------------*/
2937 static void
2938 genFunction (iCode * ic)
2939 {
2940   symbol *sym;
2941   sym_link *ftype;
2942   bool   switchedPSW = FALSE;
2943
2944   D (emitcode (";", "genFunction "););
2945
2946   _G.nRegsSaved = 0;
2947   /* create the function header */
2948   emitcode (";", "-----------------------------------------");
2949   emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
2950   emitcode (";", "-----------------------------------------");
2951
2952   emitcode ("", "%s:", sym->rname);
2953   ftype = operandType (IC_LEFT (ic));
2954
2955   if (IFFUNC_ISNAKED(ftype))
2956   {
2957       emitcode(";", "naked function: no prologue.");
2958       return;
2959   }
2960
2961   if (options.stack_probe)
2962       emitcode ("lcall","__stack_probe");
2963
2964   /* here we need to generate the equates for the
2965      register bank if required */
2966   if (FUNC_REGBANK (ftype) != rbank)
2967     {
2968       int i;
2969
2970       rbank = FUNC_REGBANK (ftype);
2971       for (i = 0; i < ds390_nRegs; i++)
2972         {
2973           if (regs390[i].print) {
2974               if (strcmp (regs390[i].base, "0") == 0)
2975                   emitcode ("", "%s !equ !constbyte",
2976                             regs390[i].dname,
2977                             8 * rbank + regs390[i].offset);
2978               else
2979                   emitcode ("", "%s !equ %s + !constbyte",
2980                             regs390[i].dname,
2981                             regs390[i].base,
2982                             8 * rbank + regs390[i].offset);
2983           }
2984         }
2985     }
2986
2987   /* if this is an interrupt service routine then
2988      save acc, b, dpl, dph  */
2989   if (IFFUNC_ISISR (sym->type))
2990       { /* is ISR */
2991       if (!inExcludeList ("acc"))
2992         emitcode ("push", "acc");
2993       if (!inExcludeList ("b"))
2994         emitcode ("push", "b");
2995       if (!inExcludeList ("dpl"))
2996         emitcode ("push", "dpl");
2997       if (!inExcludeList ("dph"))
2998         emitcode ("push", "dph");
2999       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3000         {
3001           emitcode ("push", "dpx");
3002           /* Make sure we're using standard DPTR */
3003           emitcode ("push", "dps");
3004           emitcode ("mov", "dps,#0");
3005           if (options.stack10bit)
3006             {
3007               /* This ISR could conceivably use DPTR2. Better save it. */
3008               emitcode ("push", "dpl1");
3009               emitcode ("push", "dph1");
3010               emitcode ("push", "dpx1");
3011               emitcode ("push",  DP2_RESULT_REG);
3012             }
3013         }
3014       /* if this isr has no bank i.e. is going to
3015          run with bank 0 , then we need to save more
3016          registers :-) */
3017       if (!FUNC_REGBANK (sym->type))
3018         {
3019             int i;
3020
3021           /* if this function does not call any other
3022              function then we can be economical and
3023              save only those registers that are used */
3024           if (!IFFUNC_HASFCALL(sym->type))
3025             {
3026
3027               /* if any registers used */
3028               if (sym->regsUsed)
3029                 {
3030                   /* save the registers used */
3031                   for (i = 0; i < sym->regsUsed->size; i++)
3032                     {
3033                       if (bitVectBitValue (sym->regsUsed, i))
3034                         emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
3035                     }
3036                 }
3037             }
3038           else
3039             {
3040               /* this function has  a function call cannot
3041                  determines register usage so we will have to push the
3042                  entire bank */
3043               saveRBank (0, ic, FALSE);
3044               if (options.parms_in_bank1) {
3045                   for (i=0; i < 8 ; i++ ) {
3046                       emitcode ("push","%s",rb1regs[i]);
3047                   }
3048               }
3049             }
3050         }
3051         else
3052         {
3053             /* This ISR uses a non-zero bank.
3054              *
3055              * We assume that the bank is available for our
3056              * exclusive use.
3057              *
3058              * However, if this ISR calls a function which uses some
3059              * other bank, we must save that bank entirely.
3060              */
3061             unsigned long banksToSave = 0;
3062
3063             if (IFFUNC_HASFCALL(sym->type))
3064             {
3065
3066 #define MAX_REGISTER_BANKS 4
3067
3068                 iCode *i;
3069                 int ix;
3070
3071                 for (i = ic; i; i = i->next)
3072                 {
3073                     if (i->op == ENDFUNCTION)
3074                     {
3075                         /* we got to the end OK. */
3076                         break;
3077                     }
3078
3079                     if (i->op == CALL)
3080                     {
3081                         sym_link *dtype;
3082
3083                         dtype = operandType (IC_LEFT(i));
3084                         if (dtype
3085                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3086                         {
3087                              /* Mark this bank for saving. */
3088                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3089                              {
3090                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3091                              }
3092                              else
3093                              {
3094                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3095                              }
3096
3097                              /* And note that we don't need to do it in
3098                               * genCall.
3099                               */
3100                              i->bankSaved = 1;
3101                         }
3102                     }
3103                     if (i->op == PCALL)
3104                     {
3105                         /* This is a mess; we have no idea what
3106                          * register bank the called function might
3107                          * use.
3108                          *
3109                          * The only thing I can think of to do is
3110                          * throw a warning and hope.
3111                          */
3112                         werror(W_FUNCPTR_IN_USING_ISR);
3113                     }
3114                 }
3115
3116                 if (banksToSave && options.useXstack)
3117                 {
3118                     /* Since we aren't passing it an ic,
3119                      * saveRBank will assume r0 is available to abuse.
3120                      *
3121                      * So switch to our (trashable) bank now, so
3122                      * the caller's R0 isn't trashed.
3123                      */
3124                     emitcode ("push", "psw");
3125                     emitcode ("mov", "psw,#!constbyte",
3126                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3127                     switchedPSW = TRUE;
3128                 }
3129
3130                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3131                 {
3132                      if (banksToSave & (1 << ix))
3133                      {
3134                          saveRBank(ix, NULL, FALSE);
3135                      }
3136                 }
3137             }
3138             // TODO: this needs a closer look
3139             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3140         }
3141     }
3142   else
3143     {
3144       /* if callee-save to be used for this function
3145          then save the registers being used in this function */
3146       if (IFFUNC_CALLEESAVES(sym->type))
3147         {
3148           int i;
3149
3150           /* if any registers used */
3151           if (sym->regsUsed)
3152             {
3153               /* save the registers used */
3154               for (i = 0; i < sym->regsUsed->size; i++)
3155                 {
3156                   if (bitVectBitValue (sym->regsUsed, i))
3157                     {
3158                       emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
3159                       _G.nRegsSaved++;
3160                     }
3161                 }
3162             }
3163         }
3164     }
3165
3166   /* set the register bank to the desired value */
3167   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3168    && !switchedPSW)
3169     {
3170       emitcode ("push", "psw");
3171       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3172     }
3173
3174   if ( (IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3175        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3176       if (options.stack10bit) {
3177           emitcode ("push","_bpx");
3178           emitcode ("push","_bpx+1");
3179           emitcode ("mov","_bpx,%s",spname);
3180           emitcode ("mov","_bpx+1,esp");
3181           adjustEsp("_bpx+1");
3182       } else {
3183           if (options.useXstack) {
3184               emitcode ("mov", "r0,%s", spname);
3185               emitcode ("mov", "a,_bp");
3186               emitcode ("movx", "@r0,a");
3187               emitcode ("inc", "%s", spname);
3188           } else {
3189               /* set up the stack */
3190               emitcode ("push", "_bp"); /* save the callers stack  */
3191           }
3192           emitcode ("mov", "_bp,%s", spname);
3193       }
3194   }
3195
3196   /* adjust the stack for the function */
3197   if (sym->stack) {
3198       int i = sym->stack;
3199       if (options.stack10bit) {
3200           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3201           assert (sym->recvSize <= 4);
3202           if (sym->stack <= 8) {
3203               while (i--) emitcode ("push","acc");
3204           } else {
3205               PROTECT_SP;
3206               emitcode ("mov","a,sp");
3207               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3208               emitcode ("mov","sp,a");
3209               emitcode ("mov","a,esp");
3210               adjustEsp("a");
3211               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3212               emitcode ("mov","esp,a");
3213               UNPROTECT_SP;
3214           }
3215       } else {
3216           if (i > 256)
3217               werror (W_STACK_OVERFLOW, sym->name);
3218
3219           if (i > 3 && sym->recvSize < 4) {
3220
3221               emitcode ("mov", "a,sp");
3222               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3223               emitcode ("mov", "sp,a");
3224
3225           } else
3226               while (i--)
3227                   emitcode ("inc", "sp");
3228       }
3229   }
3230
3231   if (sym->xstack)
3232     {
3233
3234       emitcode ("mov", "a,_spx");
3235       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3236       emitcode ("mov", "_spx,a");
3237     }
3238
3239   /* if critical function then turn interrupts off */
3240   if (IFFUNC_ISCRITICAL (ftype))
3241     {
3242       symbol *tlbl = newiTempLabel (NULL);
3243       emitcode ("setb", "c");
3244       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3245       emitcode ("clr", "c");
3246       emitcode ("", "%05d$:", (tlbl->key + 100));
3247       emitcode ("push", "psw"); /* save old ea via c in psw */
3248     }
3249
3250 }
3251
3252 /*-----------------------------------------------------------------*/
3253 /* genEndFunction - generates epilogue for functions               */
3254 /*-----------------------------------------------------------------*/
3255 static void
3256 genEndFunction (iCode * ic)
3257 {
3258   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3259   lineNode *lnp = lineCurr;
3260   bitVect *regsUsed;
3261   bitVect *regsUsedPrologue;
3262   bitVect *regsUnneeded;
3263   int idx;
3264
3265   D (emitcode (";", "genEndFunction "););
3266
3267   if (IFFUNC_ISNAKED(sym->type))
3268   {
3269       emitcode(";", "naked function: no epilogue.");
3270       if (options.debug && currFunc)
3271         debugFile->writeEndFunction (currFunc, ic, 0);
3272       return;
3273   }
3274
3275   if (IFFUNC_ISCRITICAL (sym->type))
3276     {
3277       emitcode ("pop", "psw"); /* restore ea via c in psw */
3278       emitcode ("mov", "ea,c");
3279     }
3280
3281   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3282        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3283
3284       if (options.stack10bit) {
3285           PROTECT_SP;
3286           emitcode ("mov", "sp,_bpx", spname);
3287           emitcode ("mov", "esp,_bpx+1", spname);
3288           UNPROTECT_SP;
3289       } else {
3290           emitcode ("mov", "%s,_bp", spname);
3291       }
3292   }
3293
3294   /* if use external stack but some variables were
3295      added to the local stack then decrement the
3296      local stack */
3297   if (options.useXstack && sym->stack) {
3298       emitcode ("mov", "a,sp");
3299       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3300       emitcode ("mov", "sp,a");
3301   }
3302
3303
3304   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3305        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3306
3307       if (options.useXstack) {
3308           emitcode ("mov", "r0,%s", spname);
3309           emitcode ("movx", "a,@r0");
3310           emitcode ("mov", "_bp,a");
3311           emitcode ("dec", "%s", spname);
3312       } else {
3313           if (options.stack10bit) {
3314               emitcode ("pop", "_bpx+1");
3315               emitcode ("pop", "_bpx");
3316           } else {
3317               emitcode ("pop", "_bp");
3318           }
3319       }
3320   }
3321
3322   /* restore the register bank  */
3323   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3324   {
3325     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3326      || !options.useXstack)
3327     {
3328         /* Special case of ISR using non-zero bank with useXstack
3329          * is handled below.
3330          */
3331         emitcode ("pop", "psw");
3332     }
3333   }
3334
3335   if (IFFUNC_ISISR (sym->type))
3336       { /* is ISR */
3337
3338       /* now we need to restore the registers */
3339       /* if this isr has no bank i.e. is going to
3340          run with bank 0 , then we need to save more
3341          registers :-) */
3342       if (!FUNC_REGBANK (sym->type))
3343         {
3344             int i;
3345           /* if this function does not call any other
3346              function then we can be economical and
3347              save only those registers that are used */
3348           if (!IFFUNC_HASFCALL(sym->type))
3349             {
3350
3351               /* if any registers used */
3352               if (sym->regsUsed)
3353                 {
3354                   /* save the registers used */
3355                   for (i = sym->regsUsed->size; i >= 0; i--)
3356                     {
3357                       if (bitVectBitValue (sym->regsUsed, i))
3358                         emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3359                     }
3360                 }
3361             }
3362           else
3363             {
3364               /* this function has  a function call cannot
3365                  determines register usage so we will have to pop the
3366                  entire bank */
3367               if (options.parms_in_bank1) {
3368                   for (i = 7 ; i >= 0 ; i-- ) {
3369                       emitcode ("pop","%s",rb1regs[i]);
3370                   }
3371               }
3372               unsaveRBank (0, ic, FALSE);
3373             }
3374         }
3375         else
3376         {
3377             /* This ISR uses a non-zero bank.
3378              *
3379              * Restore any register banks saved by genFunction
3380              * in reverse order.
3381              */
3382             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3383             int ix;
3384
3385             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3386             {
3387                 if (savedBanks & (1 << ix))
3388                 {
3389                     unsaveRBank(ix, NULL, FALSE);
3390                 }
3391             }
3392
3393             if (options.useXstack)
3394             {
3395                 /* Restore bank AFTER calling unsaveRBank,
3396                  * since it can trash r0.
3397                  */
3398                 emitcode ("pop", "psw");
3399             }
3400         }
3401
3402       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3403         {
3404           if (options.stack10bit)
3405             {
3406               emitcode ("pop", DP2_RESULT_REG);
3407               emitcode ("pop", "dpx1");
3408               emitcode ("pop", "dph1");
3409               emitcode ("pop", "dpl1");
3410             }
3411           emitcode ("pop", "dps");
3412           emitcode ("pop", "dpx");
3413         }
3414       if (!inExcludeList ("dph"))
3415         emitcode ("pop", "dph");
3416       if (!inExcludeList ("dpl"))
3417         emitcode ("pop", "dpl");
3418       if (!inExcludeList ("b"))
3419         emitcode ("pop", "b");
3420       if (!inExcludeList ("acc"))
3421         emitcode ("pop", "acc");
3422
3423       /* if debug then send end of function */
3424       if (options.debug && currFunc) {
3425           debugFile->writeEndFunction (currFunc, ic, 1);
3426         }
3427
3428       emitcode ("reti", "");
3429     }
3430   else
3431     {
3432       if (IFFUNC_CALLEESAVES(sym->type))
3433         {
3434           int i;
3435
3436           /* if any registers used */
3437           if (sym->regsUsed)
3438             {
3439               /* save the registers used */
3440               for (i = sym->regsUsed->size; i >= 0; i--)
3441                 {
3442                   if (bitVectBitValue (sym->regsUsed, i))
3443                     emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3444                 }
3445             }
3446         }
3447
3448       /* if debug then send end of function */
3449       if (options.debug && currFunc)
3450         {
3451           debugFile->writeEndFunction (currFunc, ic, 1);
3452         }
3453
3454       emitcode ("ret", "");
3455     }
3456
3457   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3458     return;
3459
3460   /* If this was an interrupt handler using bank 0 that called another */
3461   /* function, then all registers must be saved; nothing to optimized. */
3462   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3463       && !FUNC_REGBANK(sym->type))
3464     return;
3465
3466   /* There are no push/pops to optimize if not callee-saves or ISR */
3467   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3468     return;
3469
3470   /* If there were stack parameters, we cannot optimize without also    */
3471   /* fixing all of the stack offsets; this is too dificult to consider. */
3472   if (FUNC_HASSTACKPARM(sym->type))
3473     return;
3474
3475   /* Compute the registers actually used */
3476   regsUsed = newBitVect (ds390_nRegs);
3477   regsUsedPrologue = newBitVect (ds390_nRegs);
3478   while (lnp)
3479     {
3480       if (lnp->ic && lnp->ic->op == FUNCTION)
3481         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3482       else
3483         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3484
3485       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3486           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3487         break;
3488       if (!lnp->prev)
3489         break;
3490       lnp = lnp->prev;
3491     }
3492
3493   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3494       && !bitVectBitValue (regsUsed, DPS_IDX))
3495     {
3496       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3497     }
3498
3499   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3500       && !bitVectBitValue (regsUsed, CND_IDX))
3501     {
3502       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3503       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3504           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3505         bitVectUnSetBit (regsUsed, CND_IDX);
3506     }
3507   else
3508     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3509
3510   /* If this was an interrupt handler that called another function */
3511   /* function, then assume working registers may be modified by it. */
3512   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3513     {
3514       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3515       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3516       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3517       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3518       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3519       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3520       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3521       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3522       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3523       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3524       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3525     }
3526
3527   /* Remove the unneeded push/pops */
3528   regsUnneeded = newBitVect (ds390_nRegs);
3529   while (lnp)
3530     {
3531       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3532         {
3533           if (!strncmp(lnp->line, "push", 4))
3534             {
3535               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3536               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3537                 {
3538                   connectLine (lnp->prev, lnp->next);
3539                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3540                 }
3541             }
3542           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3543             {
3544               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3545               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3546                 {
3547                   connectLine (lnp->prev, lnp->next);
3548                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3549                 }
3550             }
3551         }
3552       lnp = lnp->next;
3553     }
3554
3555   for (idx = 0; idx < regsUnneeded->size; idx++)
3556     if (bitVectBitValue (regsUnneeded, idx))
3557       emitcode ("", ";\teliminated unneeded push/pop %s", ds390_regWithIdx (idx)->dname);
3558
3559   freeBitVect (regsUnneeded);
3560   freeBitVect (regsUsed);
3561   freeBitVect (regsUsedPrologue);
3562 }
3563
3564 /*-----------------------------------------------------------------*/
3565 /* genJavaNativeRet - generate code for return JavaNative          */
3566 /*-----------------------------------------------------------------*/
3567 static void genJavaNativeRet(iCode *ic)
3568 {
3569     int i, size;
3570
3571     aopOp (IC_LEFT (ic), ic, FALSE,
3572            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
3573     size = AOP_SIZE (IC_LEFT (ic));
3574
3575     assert (size <= 4);
3576
3577     /* it is assigned to GPR0-R3 then push them */
3578     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
3579         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
3580         for (i = 0 ; i < size ; i++ ) {
3581             emitcode ("push","%s",
3582                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3583         }
3584         for (i = (size-1) ; i >= 0 ; i--) {
3585             emitcode ("pop","a%s",javaRet[i]);
3586         }
3587     } else {
3588         for (i = 0 ; i < size ; i++)
3589             emitcode ("mov","%s,%s",javaRet[i],
3590                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3591     }
3592     for (i = size ; i < 4 ; i++ )
3593             emitcode ("mov","%s,#0",javaRet[i]);
3594     return;
3595 }
3596
3597 /*-----------------------------------------------------------------*/
3598 /* genRet - generate code for return statement                     */
3599 /*-----------------------------------------------------------------*/
3600 static void
3601 genRet (iCode * ic)
3602 {
3603   int size, offset = 0, pushed = 0;
3604
3605   D (emitcode (";", "genRet "););
3606
3607   /* if we have no return value then
3608      just generate the "ret" */
3609   if (!IC_LEFT (ic))
3610     goto jumpret;
3611
3612   /* if this is a JavaNative function then return
3613      value in different register */
3614   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
3615       genJavaNativeRet(ic);
3616       goto jumpret;
3617   }
3618   /* we have something to return then
3619      move the return value into place */
3620   aopOp (IC_LEFT (ic), ic, FALSE,
3621          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
3622   size = AOP_SIZE (IC_LEFT (ic));
3623
3624   _startLazyDPSEvaluation ();
3625   while (size--)
3626     {
3627       char *l;
3628       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3629         {
3630           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3631                       FALSE, TRUE, NULL);
3632           emitcode ("push", "%s", l);
3633           pushed++;
3634         }
3635       else
3636         {
3637           /* Since A is the last element of fReturn,
3638            * is is OK to clobber it in the aopGet.
3639            */
3640           l = aopGet (AOP (IC_LEFT (ic)), offset,
3641                       FALSE, FALSE, NULL);
3642           if (strcmp (fReturn[offset], l))
3643             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3644         }
3645     }
3646   _endLazyDPSEvaluation ();
3647
3648   if (pushed)
3649     {
3650       while (pushed)
3651         {
3652           pushed--;
3653           if (strcmp (fReturn[pushed], "a"))
3654             emitcode ("pop", fReturn[pushed]);
3655           else
3656             emitcode ("pop", "acc");
3657         }
3658     }
3659   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3660
3661 jumpret:
3662   /* generate a jump to the return label
3663      if the next is not the return statement */
3664   if (!(ic->next && ic->next->op == LABEL &&
3665         IC_LABEL (ic->next) == returnLabel))
3666
3667     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
3668
3669 }
3670
3671 /*-----------------------------------------------------------------*/
3672 /* genLabel - generates a label                                    */
3673 /*-----------------------------------------------------------------*/
3674 static void
3675 genLabel (iCode * ic)
3676 {
3677   /* special case never generate */
3678   if (IC_LABEL (ic) == entryLabel)
3679     return;
3680
3681   D (emitcode (";", "genLabel ");
3682     );
3683
3684   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
3685 }
3686
3687 /*-----------------------------------------------------------------*/
3688 /* genGoto - generates a ljmp                                      */
3689 /*-----------------------------------------------------------------*/
3690 static void
3691 genGoto (iCode * ic)
3692 {
3693   D (emitcode (";", "genGoto ");
3694     );
3695   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
3696 }
3697
3698 /*-----------------------------------------------------------------*/
3699 /* findLabelBackwards: walks back through the iCode chain looking  */
3700 /* for the given label. Returns number of iCode instructions     */
3701 /* between that label and given ic.          */
3702 /* Returns zero if label not found.          */
3703 /*-----------------------------------------------------------------*/
3704 static int
3705 findLabelBackwards (iCode * ic, int key)
3706 {
3707   int count = 0;
3708
3709   while (ic->prev)
3710     {
3711       ic = ic->prev;
3712       count++;
3713
3714       /* If we have any pushes or pops, we cannot predict the distance.
3715          I don't like this at all, this should be dealt with in the
3716          back-end */
3717       if (ic->op == IPUSH || ic->op == IPOP) {
3718         return 0;
3719       }
3720
3721       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3722         {
3723           /* printf("findLabelBackwards = %d\n", count); */
3724           return count;
3725         }
3726     }
3727
3728   return 0;
3729 }
3730
3731 /*-----------------------------------------------------------------*/
3732 /* genPlusIncr :- does addition with increment if possible         */
3733 /*-----------------------------------------------------------------*/
3734 static bool
3735 genPlusIncr (iCode * ic)
3736 {
3737   unsigned int icount;
3738   unsigned int size = getDataSize (IC_RESULT (ic));
3739
3740   /* will try to generate an increment */
3741   /* if the right side is not a literal
3742      we cannot */
3743   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3744     return FALSE;
3745
3746   /* if the literal value of the right hand side
3747      is greater than 4 then it is not worth it */
3748   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3749     return FALSE;
3750
3751   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
3752       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
3753       while (icount--) {
3754           emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
3755       }
3756       return TRUE;
3757   }
3758   /* if increment 16 bits in register */
3759   if (
3760        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3761        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3762        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3763        (size > 1) &&
3764        (icount == 1))
3765     {
3766       symbol  *tlbl;
3767       int     emitTlbl;
3768       int     labelRange;
3769       char    *l;
3770
3771       /* If the next instruction is a goto and the goto target
3772        * is <= 5 instructions previous to this, we can generate
3773        * jumps straight to that target.
3774        */
3775       if (ic->next && ic->next->op == GOTO
3776           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3777           && labelRange <= 5)
3778         {
3779           D(emitcode (";", "tail increment optimized (range %d)", labelRange););
3780           tlbl = IC_LABEL (ic->next);
3781           emitTlbl = 0;
3782         }
3783       else
3784         {
3785           tlbl = newiTempLabel (NULL);
3786           emitTlbl = 1;
3787         }
3788
3789       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
3790       emitcode ("inc", "%s", l);
3791
3792       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3793           IS_AOP_PREG (IC_RESULT (ic)))
3794       {
3795         emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3796       }
3797       else
3798       {
3799           emitcode ("clr", "a");
3800           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3801       }
3802
3803       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL);
3804       emitcode ("inc", "%s", l);
3805       if (size > 2)
3806         {
3807             if (!strcmp(l, "acc"))
3808             {
3809                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3810             }
3811             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3812                      IS_AOP_PREG (IC_RESULT (ic)))
3813             {
3814                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3815             }
3816             else
3817             {
3818                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3819             }
3820
3821             l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
3822             emitcode ("inc", "%s", l);
3823         }
3824       if (size > 3)
3825         {
3826             if (!strcmp(l, "acc"))
3827             {
3828                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3829             }
3830             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3831                      IS_AOP_PREG (IC_RESULT (ic)))
3832             {
3833                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3834             }
3835             else
3836             {
3837                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3838             }
3839
3840             l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
3841             emitcode ("inc", "%s", l);  }
3842
3843       if (emitTlbl)
3844         {
3845           emitcode ("", "!tlabeldef", tlbl->key + 100);
3846         }
3847       return TRUE;
3848     }
3849
3850   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
3851       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
3852       options.model == MODEL_FLAT24 ) {
3853
3854       switch (size) {
3855       case 3:
3856           emitcode ("mov","dpx,%s",aopGet(AOP (IC_LEFT (ic)), 2, FALSE, FALSE, NULL));
3857       case 2:
3858           emitcode ("mov","dph,%s",aopGet(AOP (IC_LEFT (ic)), 1, FALSE, FALSE, NULL));
3859       case 1:
3860           emitcode ("mov","dpl,%s",aopGet(AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3861           break;
3862       }
3863       while (icount--) emitcode ("inc","dptr");
3864       return TRUE;
3865   }
3866
3867   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
3868       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
3869       icount <= 5 ) {
3870       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
3871       while (icount--) emitcode ("inc","dptr");
3872       emitcode ("mov","dps,#0");
3873       return TRUE;
3874   }
3875
3876   /* if the sizes are greater than 1 then we cannot */
3877   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3878       AOP_SIZE (IC_LEFT (ic)) > 1)
3879     return FALSE;
3880
3881   /* we can if the aops of the left & result match or
3882      if they are in registers and the registers are the
3883      same */
3884   if (
3885        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3886        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3887        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3888     {
3889
3890       if (icount > 3)
3891         {
3892           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3893           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
3894           aopPut (AOP (IC_RESULT (ic)), "a", 0);
3895         }
3896       else
3897         {
3898
3899           _startLazyDPSEvaluation ();
3900           while (icount--)
3901             {
3902               emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3903             }
3904           _endLazyDPSEvaluation ();
3905         }
3906
3907       return TRUE;
3908     }
3909
3910   return FALSE;
3911 }
3912
3913 /*-----------------------------------------------------------------*/
3914 /* outBitAcc - output a bit in acc                                 */
3915 /*-----------------------------------------------------------------*/
3916 static void
3917 outBitAcc (operand * result)
3918 {
3919   symbol *tlbl = newiTempLabel (NULL);
3920   /* if the result is a bit */
3921   if (AOP_TYPE (result) == AOP_CRY)
3922     {
3923       aopPut (AOP (result), "a", 0);
3924     }
3925   else
3926     {
3927       emitcode ("jz", "!tlabel", tlbl->key + 100);
3928       emitcode ("mov", "a,%s", one);
3929       emitcode ("", "!tlabeldef", tlbl->key + 100);
3930       outAcc (result);
3931     }
3932 }
3933
3934 /*-----------------------------------------------------------------*/
3935 /* genPlusBits - generates code for addition of two bits           */
3936 /*-----------------------------------------------------------------*/
3937 static void
3938 genPlusBits (iCode * ic)
3939 {
3940   D (emitcode (";", "genPlusBits "););
3941
3942   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3943     {
3944       symbol *lbl = newiTempLabel (NULL);
3945       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3946       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3947       emitcode ("cpl", "c");
3948       emitcode ("", "!tlabeldef", (lbl->key + 100));
3949       outBitC (IC_RESULT (ic));
3950     }
3951   else
3952     {
3953       emitcode ("clr", "a");
3954       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3955       emitcode ("rlc", "a");
3956       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3957       emitcode ("addc", "a,#0");
3958       outAcc (IC_RESULT (ic));
3959     }
3960 }
3961
3962 static void
3963 adjustArithmeticResult (iCode * ic)
3964 {
3965   if (opIsGptr (IC_RESULT (ic)) &&
3966       opIsGptr (IC_LEFT (ic)) &&
3967       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3968     {
3969       aopPut (AOP (IC_RESULT (ic)),
3970               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3971               GPTRSIZE - 1);
3972     }
3973
3974   if (opIsGptr (IC_RESULT (ic)) &&
3975       opIsGptr (IC_RIGHT (ic)) &&
3976       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3977     {
3978       aopPut (AOP (IC_RESULT (ic)),
3979             aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3980               GPTRSIZE - 1);
3981     }
3982
3983   if (opIsGptr (IC_RESULT (ic)) &&
3984       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3985       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3986       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3987       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3988     {
3989       char buff[5];
3990       SNPRINTF (buff, sizeof(buff),
3991                 "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3992       aopPut (AOP (IC_RESULT (ic)), buff, GPTRSIZE - 1);
3993     }
3994 }
3995
3996 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
3997 // generates the result if possible. If result is generated, returns TRUE; otherwise
3998 // returns false and caller must deal with fact that result isn't aopOp'd.
3999 bool aopOp3(iCode * ic)
4000 {
4001     bool dp1InUse, dp2InUse;
4002     bool useDp2;
4003
4004     // First, generate the right opcode. DPTR may be used if neither left nor result are
4005     // of type AOP_STR.
4006
4007 //    D(emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4008 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4009 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4010 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4011 //      );
4012 //    D(emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4013 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4014 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4015 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4016 //      );
4017
4018     // Right uses DPTR unless left or result is an AOP_STR; however,
4019     // if right is an AOP_STR, it must use DPTR regardless.
4020     if ((AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)))
4021      && !AOP_IS_STR(IC_RIGHT(ic)))
4022     {
4023         useDp2 = TRUE;
4024     }
4025     else
4026     {
4027         useDp2 = FALSE;
4028     }
4029
4030     aopOp (IC_RIGHT(ic),ic,FALSE, useDp2);
4031
4032     // if the right used DPTR, left MUST use DPTR2.
4033     // if the right used DPTR2, left MUST use DPTR.
4034     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4035     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4036     // enabling us to assign DPTR to result.
4037
4038     if (AOP_USESDPTR(IC_RIGHT(ic)))
4039     {
4040         useDp2 = TRUE;
4041     }
4042     else if (AOP_USESDPTR2(IC_RIGHT(ic)))
4043     {
4044         useDp2 = FALSE;
4045     }
4046     else
4047     {
4048         if (AOP_IS_STR(IC_RESULT(ic)) && !AOP_IS_STR(IC_LEFT(ic)))
4049         {
4050             useDp2 = TRUE;
4051         }
4052         else
4053         {
4054             useDp2 = FALSE;
4055         }
4056     }
4057
4058     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
4059
4060
4061     // We've op'd the left & right. So, if left or right are the same operand as result,
4062     // we know aopOp will succeed, and we can just do it & bail.
4063     if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)))
4064       {
4065         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4066         return TRUE;
4067       }
4068     if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
4069       {
4070 //      D(emitcode(";", "aopOp3: (left | right) & result equal"););
4071         aopOp(IC_RESULT(ic),ic,TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4072         return TRUE;
4073       }
4074
4075     // Operands may be equivalent (but not equal) if they share a spill location. If
4076     // so, use the same DPTR or DPTR2.
4077     if (operandsEqu (IC_LEFT(ic), IC_RESULT(ic)))
4078       {
4079         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4080         return TRUE;
4081       }
4082     if (operandsEqu (IC_RIGHT(ic), IC_RESULT(ic)))
4083       {
4084         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4085         return TRUE;
4086       }
4087
4088     // Note which dptrs are currently in use.
4089     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
4090     dp2InUse = AOP_USESDPTR2(IC_LEFT(ic)) || AOP_USESDPTR2(IC_RIGHT(ic));
4091
4092     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4093     // generate it.
4094     if (dp1InUse && AOP_IS_STR(IC_RESULT(ic)))
4095     {
4096         return FALSE;
4097     }
4098
4099     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4100     if (dp2InUse && AOP_IS_DPTRn(IC_RESULT(ic)))
4101     {
4102         return FALSE;
4103     }
4104
4105     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4106     if (dp1InUse && dp2InUse && isOperandInFarSpace(IC_RESULT(ic)))
4107     {
4108         return FALSE;
4109     }
4110
4111     aopOp (IC_RESULT(ic),ic,TRUE, dp1InUse);
4112
4113     // Some sanity checking...
4114     if (dp1InUse && AOP_USESDPTR(IC_RESULT(ic)))
4115     {
4116         fprintf(stderr,
4117                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4118                 __FILE__, __LINE__, ic->filename, ic->lineno);
4119         emitcode(";", ">>> unexpected DPTR here.");
4120     }
4121
4122     if (dp2InUse && AOP_USESDPTR2(IC_RESULT(ic)))
4123     {
4124         fprintf(stderr,
4125                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4126                 __FILE__, __LINE__, ic->filename, ic->lineno);
4127         emitcode(";", ">>> unexpected DPTR2 here.");
4128     }
4129
4130     return TRUE;
4131 }
4132
4133 // Macro to aopOp all three operands of an ic. If this cannot be done,
4134 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4135 // will be set TRUE. The caller must then handle the case specially, noting
4136 // that the IC_RESULT operand is not aopOp'd.
4137 //
4138 #define AOP_OP_3_NOFATAL(ic, rc) \
4139             do { rc = !aopOp3(ic); } while (0)
4140
4141 // aopOp the left & right operands of an ic.
4142 #define AOP_OP_2(ic) \
4143     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic))); \
4144     aopOp (IC_LEFT(ic),ic,FALSE, AOP_USESDPTR(IC_RIGHT(ic)));
4145
4146 // convienience macro.
4147 #define AOP_SET_LOCALS(ic) \
4148     left = IC_LEFT(ic); \
4149     right = IC_RIGHT(ic); \
4150     result = IC_RESULT(ic);
4151
4152
4153 // Given an integer value of pushedSize bytes on the stack,
4154 // adjust it to be resultSize bytes, either by discarding
4155 // the most significant bytes or by zero-padding.
4156 //
4157 // On exit from this macro, pushedSize will have been adjusted to
4158 // equal resultSize, and ACC may be trashed.
4159 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4160       /* If the pushed data is bigger than the result,          \
4161        * simply discard unused bytes. Icky, but works.          \
4162        */                                                       \
4163       while (pushedSize > resultSize)                           \
4164       {                                                         \
4165           D (emitcode (";", "discarding unused result byte."););\
4166           emitcode ("pop", "acc");                              \
4167           pushedSize--;                                         \
4168       }                                                         \
4169       if (pushedSize < resultSize)                              \
4170       {                                                         \
4171           emitcode ("clr", "a");                                \
4172           /* Conversly, we haven't pushed enough here.          \
4173            * just zero-pad, and all is well.                    \
4174            */                                                   \
4175           while (pushedSize < resultSize)                       \
4176           {                                                     \
4177               emitcode("push", "acc");                          \
4178               pushedSize++;                                     \
4179           }                                                     \
4180       }                                                         \
4181       assert(pushedSize == resultSize);
4182
4183 /*-----------------------------------------------------------------*/
4184 /* genPlus - generates code for addition                           */
4185 /*-----------------------------------------------------------------*/
4186 static void
4187 genPlus (iCode * ic)
4188 {
4189   int size, offset = 0;
4190   bool pushResult;
4191   int rSize;
4192
4193   D (emitcode (";", "genPlus "););
4194
4195   /* special cases :- */
4196   if ( AOP_IS_STR(IC_LEFT(ic)) &&
4197       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
4198       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4199       size = (int)floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
4200       if (size <= 9) {
4201           while (size--) emitcode ("inc","dptr");
4202       } else {
4203           emitcode ("mov","a,dpl");
4204           emitcode ("add","a,#!constbyte",size & 0xff);
4205           emitcode ("mov","dpl,a");
4206           emitcode ("mov","a,dph");
4207           emitcode ("addc","a,#!constbyte",(size >> 8) & 0xff);
4208           emitcode ("mov","dph,a");
4209           emitcode ("mov","a,dpx");
4210           emitcode ("addc","a,#!constbyte",(size >> 16) & 0xff);
4211           emitcode ("mov","dpx,a");
4212       }
4213       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4214       return ;
4215   }
4216   if ( IS_SYMOP(IC_LEFT(ic)) &&
4217        OP_SYMBOL(IC_LEFT(ic))->remat &&
4218        isOperandInFarSpace(IC_RIGHT(ic))) {
4219       operand *op = IC_RIGHT(ic);
4220       IC_RIGHT(ic) = IC_LEFT(ic);
4221       IC_LEFT(ic) = op;
4222   }
4223
4224   AOP_OP_3_NOFATAL (ic, pushResult);
4225
4226   if (pushResult)
4227     {
4228       D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
4229     }
4230
4231   if (!pushResult)
4232     {
4233       /* if literal, literal on the right or
4234          if left requires ACC or right is already
4235          in ACC */
4236       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4237        || ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
4238           || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4239         {
4240           operand *t = IC_RIGHT (ic);
4241           IC_RIGHT (ic) = IC_LEFT (ic);
4242           IC_LEFT (ic) = t;
4243           emitcode (";", "Swapped plus args.");
4244         }
4245
4246       /* if both left & right are in bit
4247          space */
4248       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4249           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4250         {
4251           genPlusBits (ic);
4252           goto release;
4253         }
4254
4255       /* if left in bit space & right literal */
4256       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4257           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4258         {
4259           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4260           /* if result in bit space */
4261           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4262             {
4263               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4264                 emitcode ("cpl", "c");
4265               outBitC (IC_RESULT (ic));
4266             }
4267           else
4268             {
4269               size = getDataSize (IC_RESULT (ic));
4270               _startLazyDPSEvaluation ();
4271               while (size--)
4272                 {
4273                   MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4274                   emitcode ("addc", "a,#0");
4275                   aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4276                 }
4277               _endLazyDPSEvaluation ();
4278             }
4279           goto release;
4280         }
4281
4282       /* if I can do an increment instead
4283          of add then GOOD for ME */
4284       if (genPlusIncr (ic) == TRUE)
4285         {
4286           emitcode (";", "did genPlusIncr");
4287           goto release;
4288         }
4289
4290     }
4291   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4292
4293   _startLazyDPSEvaluation ();
4294   while (size--)
4295     {
4296       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4297         {
4298           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4299           if (offset == 0)
4300             emitcode ("add", "a,%s",
4301                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4302           else
4303             emitcode ("addc", "a,%s",
4304                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4305         }
4306       else
4307         {
4308           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4309           {
4310               /* right is going to use ACC or we would have taken the
4311                * above branch.
4312                */
4313               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4314        TR_AP("#3");
4315               D(emitcode(";", "+ AOP_ACC special case."););
4316               emitcode("xch", "a, %s", DP2_RESULT_REG);
4317           }
4318           MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4319           if (offset == 0)
4320           {
4321             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4322             {
4323          TR_AP("#4");
4324                 emitcode("add", "a, %s", DP2_RESULT_REG);
4325             }
4326             else
4327             {
4328                 emitcode ("add", "a,%s",
4329                           aopGet (AOP(IC_LEFT(ic)), offset, FALSE, FALSE,
4330                                   DP2_RESULT_REG));
4331             }
4332           }
4333           else
4334           {
4335             emitcode ("addc", "a,%s",
4336                   aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE,
4337                           DP2_RESULT_REG));
4338           }
4339         }
4340       if (!pushResult)
4341         {
4342           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4343         }
4344       else
4345         {
4346           emitcode ("push", "acc");
4347         }
4348       offset++;
4349     }
4350   _endLazyDPSEvaluation ();
4351
4352   if (pushResult)
4353     {
4354       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4355
4356       size = getDataSize (IC_LEFT (ic));
4357       rSize = getDataSize (IC_RESULT (ic));
4358
4359       ADJUST_PUSHED_RESULT(size, rSize);
4360
4361       _startLazyDPSEvaluation ();
4362       while (size--)
4363         {
4364           emitcode ("pop", "acc");
4365           aopPut (AOP (IC_RESULT (ic)), "a", size);
4366         }
4367       _endLazyDPSEvaluation ();
4368     }
4369
4370   adjustArithmeticResult (ic);
4371
4372 release:
4373   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4374   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4375   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4376 }
4377
4378 /*-----------------------------------------------------------------*/
4379 /* genMinusDec :- does subtraction with deccrement if possible     */
4380 /*-----------------------------------------------------------------*/
4381 static bool
4382 genMinusDec (iCode * ic)
4383 {
4384   unsigned int icount;
4385   unsigned int size = getDataSize (IC_RESULT (ic));
4386
4387   /* will try to generate an increment */
4388   /* if the right side is not a literal
4389      we cannot */
4390   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4391     return FALSE;
4392
4393   /* if the literal value of the right hand side
4394      is greater than 4 then it is not worth it */
4395   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4396     return FALSE;
4397
4398   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4399       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4400       while (icount--) {
4401           emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
4402       }
4403       return TRUE;
4404   }
4405   /* if decrement 16 bits in register */
4406   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4407       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4408       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4409       (size > 1) &&
4410       (icount == 1))
4411     {
4412       symbol *tlbl;
4413       int    emitTlbl;
4414       int    labelRange;
4415       char   *l;
4416
4417       /* If the next instruction is a goto and the goto target
4418          * is <= 5 instructions previous to this, we can generate
4419          * jumps straight to that target.
4420        */
4421       if (ic->next && ic->next->op == GOTO
4422           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4423           && labelRange <= 5)
4424         {
4425           emitcode (";", "tail decrement optimized (range %d)", labelRange);
4426           tlbl = IC_LABEL (ic->next);
4427           emitTlbl = 0;
4428         }
4429       else
4430         {
4431           tlbl = newiTempLabel (NULL);
4432           emitTlbl = 1;
4433         }
4434
4435       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
4436       emitcode ("dec", "%s", l);
4437
4438       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4439           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4440           IS_AOP_PREG (IC_RESULT (ic)))
4441       {
4442           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4443       }
4444       else
4445       {
4446           emitcode ("mov", "a,#!constbyte",0xff);
4447           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4448       }
4449       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL);
4450       emitcode ("dec", "%s", l);
4451       if (size > 2)
4452         {
4453             if (!strcmp(l, "acc"))
4454             {
4455                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4456             }
4457             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4458                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4459                      IS_AOP_PREG (IC_RESULT (ic)))
4460             {
4461                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4462             }
4463             else
4464             {
4465                 emitcode ("mov", "a,#!constbyte",0xff);
4466                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4467             }
4468             l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
4469             emitcode ("dec", "%s", l);
4470         }
4471       if (size > 3)
4472         {
4473             if (!strcmp(l, "acc"))
4474             {
4475                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4476             }
4477             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4478                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4479                      IS_AOP_PREG (IC_RESULT (ic)))
4480             {
4481                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4482             }
4483             else
4484             {
4485                 emitcode ("mov", "a,#!constbyte",0xff);
4486                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4487             }
4488             l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
4489             emitcode ("dec", "%s", l);
4490         }
4491       if (emitTlbl)
4492         {
4493           emitcode ("", "!tlabeldef", tlbl->key + 100);
4494         }
4495       return TRUE;
4496     }
4497
4498   /* if the sizes are greater than 1 then we cannot */
4499   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4500       AOP_SIZE (IC_LEFT (ic)) > 1)
4501     return FALSE;
4502
4503   /* we can if the aops of the left & result match or
4504      if they are in registers and the registers are the
4505      same */
4506   if (
4507        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4508        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4509        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4510     {
4511
4512       _startLazyDPSEvaluation ();
4513       while (icount--)
4514         {
4515           emitcode ("dec", "%s",
4516                     aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
4517         }
4518       _endLazyDPSEvaluation ();
4519
4520       return TRUE;
4521     }
4522
4523   return FALSE;
4524 }
4525
4526 /*-----------------------------------------------------------------*/
4527 /* addSign - complete with sign                                    */
4528 /*-----------------------------------------------------------------*/
4529 static void
4530 addSign (operand * result, int offset, int sign)
4531 {
4532   int size = (getDataSize (result) - offset);
4533   if (size > 0)
4534     {
4535       _startLazyDPSEvaluation();
4536       if (sign)
4537         {
4538           emitcode ("rlc", "a");
4539           emitcode ("subb", "a,acc");
4540           while (size--)
4541           {
4542             aopPut (AOP (result), "a", offset++);
4543           }
4544         }
4545       else
4546       {
4547         while (size--)
4548         {
4549           aopPut (AOP (result), zero, offset++);
4550         }
4551       }
4552       _endLazyDPSEvaluation();
4553     }
4554 }
4555
4556 /*-----------------------------------------------------------------*/
4557 /* genMinusBits - generates code for subtraction  of two bits      */
4558 /*-----------------------------------------------------------------*/
4559 static void
4560 genMinusBits (iCode * ic)
4561 {
4562   symbol *lbl = newiTempLabel (NULL);
4563
4564   D (emitcode (";", "genMinusBits "););
4565
4566   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4567     {
4568       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4569       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4570       emitcode ("cpl", "c");
4571       emitcode ("", "!tlabeldef", (lbl->key + 100));
4572       outBitC (IC_RESULT (ic));
4573     }
4574   else
4575     {
4576       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4577       emitcode ("subb", "a,acc");
4578       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4579       emitcode ("inc", "a");
4580       emitcode ("", "!tlabeldef", (lbl->key + 100));
4581       aopPut (AOP (IC_RESULT (ic)), "a", 0);
4582       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4583     }
4584 }
4585
4586 /*-----------------------------------------------------------------*/
4587 /* genMinus - generates code for subtraction                       */
4588 /*-----------------------------------------------------------------*/
4589 static void
4590 genMinus (iCode * ic)
4591 {
4592     int size, offset = 0;
4593     int rSize;
4594     long lit = 0L;
4595     bool pushResult;
4596
4597     D (emitcode (";", "genMinus "););
4598
4599     AOP_OP_3_NOFATAL(ic, pushResult);
4600
4601     if (!pushResult)
4602     {
4603       /* special cases :- */
4604       /* if both left & right are in bit space */
4605       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4606           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4607         {
4608           genMinusBits (ic);
4609           goto release;
4610         }
4611
4612       /* if I can do an decrement instead
4613          of subtract then GOOD for ME */
4614       if (genMinusDec (ic) == TRUE)
4615         goto release;
4616
4617     }
4618
4619   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4620
4621   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4622     {
4623       CLRC;
4624     }
4625   else
4626     {
4627       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4628       lit = -lit;
4629     }
4630
4631
4632   /* if literal, add a,#-lit, else normal subb */
4633   _startLazyDPSEvaluation ();
4634   while (size--) {
4635       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
4636           if (AOP_USESDPTR(IC_RIGHT(ic))) {
4637               emitcode ("mov","b,%s",
4638                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4639               MOVA(aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4640               emitcode ("subb","a,b");
4641           } else {
4642               MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4643               emitcode ("subb", "a,%s",
4644                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE,
4645                                 DP2_RESULT_REG));
4646           }
4647       } else {
4648           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4649           /* first add without previous c */
4650           if (!offset) {
4651               if (!size && lit==-1) {
4652                   emitcode ("dec", "a");
4653               } else {
4654                   emitcode ("add", "a,#!constbyte",
4655                             (unsigned int) (lit & 0x0FFL));
4656               }
4657           } else {
4658               emitcode ("addc", "a,#!constbyte",
4659                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4660           }
4661       }
4662
4663       if (pushResult) {
4664           emitcode ("push", "acc");
4665       } else {
4666           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4667       }
4668       offset++;
4669   }
4670   _endLazyDPSEvaluation ();
4671
4672   if (pushResult)
4673     {
4674       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4675
4676       size = getDataSize (IC_LEFT (ic));
4677       rSize = getDataSize (IC_RESULT (ic));
4678
4679       ADJUST_PUSHED_RESULT(size, rSize);
4680
4681       _startLazyDPSEvaluation ();
4682       while (size--)
4683         {
4684           emitcode ("pop", "acc");
4685           aopPut (AOP (IC_RESULT (ic)), "a", size);
4686         }
4687       _endLazyDPSEvaluation ();
4688     }
4689
4690   adjustArithmeticResult (ic);
4691
4692 release:
4693   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4694   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4695   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4696 }
4697
4698
4699 /*-----------------------------------------------------------------*/
4700 /* genMultbits :- multiplication of bits                           */
4701 /*-----------------------------------------------------------------*/
4702 static void
4703 genMultbits (operand * left,
4704              operand * right,
4705              operand * result,
4706              iCode   * ic)
4707 {
4708   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4709   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4710   aopOp(result, ic, TRUE, FALSE);
4711   outBitC (result);
4712 }
4713
4714
4715 /*-----------------------------------------------------------------*/
4716 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4717 /*-----------------------------------------------------------------*/
4718 static void
4719 genMultOneByte (operand * left,
4720                 operand * right,
4721                 operand * result,
4722                 iCode   * ic)
4723 {
4724   int size;
4725   symbol *lbl;
4726   bool runtimeSign, compiletimeSign;
4727   bool lUnsigned, rUnsigned;
4728
4729
4730   /* (if two literals: the value is computed before) */
4731   /* if one literal, literal on the right */
4732   if (AOP_TYPE (left) == AOP_LIT)
4733     {
4734       operand *t = right;
4735       right = left;
4736       left = t;
4737       emitcode (";", "swapped left and right");
4738     }
4739
4740   /* (if two literals: the value is computed before) */
4741   /* if one literal, literal on the right */
4742   if (AOP_TYPE (left) == AOP_LIT)
4743     {
4744       operand *t = right;
4745       right = left;
4746       left = t;
4747       /* emitcode (";", "swapped left and right"); */
4748     }
4749   /* if no literal, unsigned on the right: shorter code */
4750   if (   AOP_TYPE (right) != AOP_LIT
4751       && SPEC_USIGN (getSpec (operandType (left))))
4752     {
4753       operand *t = right;
4754       right = left;
4755       left = t;
4756     }
4757
4758   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4759   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4760
4761   if ((lUnsigned && rUnsigned)
4762 /* sorry, I don't know how to get size
4763    without calling aopOp (result,...);
4764    see Feature Request  */
4765       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
4766                    no need to take care about the signedness! */
4767     {
4768       /* just an unsigned 8 * 8 = 8 multiply
4769          or 8u * 8u = 16u */
4770       /* emitcode (";","unsigned"); */
4771       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4772       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4773       emitcode ("mul", "ab");
4774
4775       _G.accInUse++; _G.bInUse++;
4776       aopOp (result, ic, TRUE, FALSE);
4777       size = AOP_SIZE (result);
4778
4779       if (size < 1 || size > 2)
4780         {
4781           /* this should never happen */
4782           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4783                    size, __FILE__, lineno);
4784           exit (1);
4785         }
4786
4787       aopPut (AOP (result), "a", 0);
4788       _G.accInUse--; _G.bInUse--;
4789       if (size == 2)
4790         aopPut (AOP (result), "b", 1);
4791       return;
4792     }
4793
4794   /* we have to do a signed multiply */
4795   /* emitcode (";", "signed"); */
4796
4797   /* now sign adjust for both left & right */
4798
4799   /* let's see what's needed: */
4800   /* apply negative sign during runtime */
4801   runtimeSign = FALSE;
4802   /* negative sign from literals */
4803   compiletimeSign = FALSE;
4804
4805   if (!lUnsigned)
4806     {
4807       if (AOP_TYPE(left) == AOP_LIT)
4808         {
4809           /* signed literal */
4810           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4811           if (val < 0)
4812             compiletimeSign = TRUE;
4813         }
4814       else
4815         /* signed but not literal */
4816         runtimeSign = TRUE;
4817     }
4818
4819   if (!rUnsigned)
4820     {
4821       if (AOP_TYPE(right) == AOP_LIT)
4822         {
4823           /* signed literal */
4824           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4825           if (val < 0)
4826             compiletimeSign ^= TRUE;
4827         }
4828       else
4829         /* signed but not literal */
4830         runtimeSign = TRUE;
4831     }
4832
4833   /* initialize F0, which stores the runtime sign */
4834   if (runtimeSign)
4835     {
4836       if (compiletimeSign)
4837         emitcode ("setb", "F0"); /* set sign flag */
4838       else
4839         emitcode ("clr", "F0"); /* reset sign flag */
4840     }
4841
4842   /* save the signs of the operands */
4843   if (AOP_TYPE(right) == AOP_LIT)
4844     {
4845       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4846
4847       if (!rUnsigned && val < 0)
4848         emitcode ("mov", "b,#!constbyte", -val);
4849       else
4850         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
4851     }
4852   else /* ! literal */
4853     {
4854       if (rUnsigned)  /* emitcode (";", "signed"); */
4855         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4856       else
4857         {
4858           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4859           lbl = newiTempLabel (NULL);
4860           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
4861           emitcode ("cpl", "F0"); /* complement sign flag */
4862           emitcode ("cpl", "a");  /* 2's complement */
4863           emitcode ("inc", "a");
4864           emitcode ("", "!tlabeldef", lbl->key + 100);
4865           emitcode ("mov", "b,a");
4866         }
4867     }
4868
4869   if (AOP_TYPE(left) == AOP_LIT)
4870     {
4871       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4872
4873       if (!lUnsigned && val < 0)
4874         emitcode ("mov", "a,#!constbyte", -val);
4875       else
4876         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
4877     }
4878   else /* ! literal */
4879     {
4880       if (lUnsigned)  /* emitcode (";", "signed"); */
4881
4882         emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4883       else
4884         {
4885           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4886           lbl = newiTempLabel (NULL);
4887           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
4888           emitcode ("cpl", "F0"); /* complement sign flag */
4889           emitcode ("cpl", "a");  /* 2's complement */
4890           emitcode ("inc", "a");
4891           emitcode ("", "!tlabeldef", lbl->key + 100);
4892         }
4893     }
4894
4895   /* now the multiplication */
4896   emitcode ("mul", "ab");
4897   _G.accInUse++;_G.bInUse++;
4898   aopOp(result, ic, TRUE, FALSE);
4899   size = AOP_SIZE (result);
4900
4901   if (size < 1 || size > 2)
4902     {
4903       /* this should never happen */
4904       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4905                size, __FILE__, lineno);
4906       exit (1);
4907     }
4908
4909   if (runtimeSign || compiletimeSign)
4910     {
4911       lbl = newiTempLabel (NULL);
4912       if (runtimeSign)
4913         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
4914       emitcode ("cpl", "a"); /* lsb 2's complement */
4915       if (size != 2)
4916         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4917       else
4918         {
4919           emitcode ("add", "a,#1"); /* this sets carry flag */
4920           emitcode ("xch", "a,b");
4921           emitcode ("cpl", "a"); /* msb 2's complement */
4922           emitcode ("addc", "a,#0");
4923           emitcode ("xch", "a,b");
4924         }
4925       emitcode ("", "!tlabeldef", lbl->key + 100);
4926     }
4927   aopPut (AOP (result), "a", 0);
4928   _G.accInUse--;_G.bInUse--;
4929   if (size == 2)
4930     aopPut (AOP (result), "b", 1);
4931 }
4932
4933 /*-----------------------------------------------------------------*/
4934 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
4935 /*-----------------------------------------------------------------*/
4936 static void genMultTwoByte (operand *left, operand *right,
4937                             operand *result, iCode *ic)
4938 {
4939         sym_link *retype = getSpec(operandType(right));
4940         sym_link *letype = getSpec(operandType(left));
4941         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
4942         symbol *lbl;
4943
4944         if (AOP_TYPE (left) == AOP_LIT) {
4945                 operand *t = right;
4946                 right = left;
4947                 left = t;
4948         }
4949         /* save EA bit in F1 */
4950         lbl = newiTempLabel(NULL);
4951         emitcode ("setb","F1");
4952         emitcode ("jbc","EA,!tlabel",lbl->key+100);
4953         emitcode ("clr","F1");
4954         emitcode("","!tlabeldef",lbl->key+100);
4955
4956         /* load up MB with right */
4957         if (!umult) {
4958                 emitcode("clr","F0");
4959                 if (AOP_TYPE(right) == AOP_LIT) {
4960                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
4961                         if (val < 0) {
4962                                 emitcode("setb","F0");
4963                                 val = -val;
4964                         }
4965                         emitcode ("mov","mb,#!constbyte",val & 0xff);
4966                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
4967                 } else {
4968                         lbl = newiTempLabel(NULL);
4969                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4970                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4971                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4972                         emitcode ("xch", "a,b");
4973                         emitcode ("cpl","a");
4974                         emitcode ("add", "a,#1");
4975                         emitcode ("xch", "a,b");
4976                         emitcode ("cpl", "a"); // msb
4977                         emitcode ("addc", "a,#0");
4978                         emitcode ("setb","F0");
4979                         emitcode ("","!tlabeldef",lbl->key+100);
4980                         emitcode ("mov","mb,b");
4981                         emitcode ("mov","mb,a");
4982                 }
4983         } else {
4984                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4985                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4986         }
4987         /* load up MA with left */
4988         if (!umult) {
4989                 lbl = newiTempLabel(NULL);
4990                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4991                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4992                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4993                 emitcode ("xch", "a,b");
4994                 emitcode ("cpl","a");
4995                 emitcode ("add", "a,#1");
4996                 emitcode ("xch", "a,b");
4997                 emitcode ("cpl", "a"); // msb
4998                 emitcode ("addc","a,#0");
4999                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5000                 emitcode ("setb","F0");
5001                 emitcode ("","!tlabeldef",lbl->key+100);
5002                 emitcode ("mov","ma,b");
5003                 emitcode ("mov","ma,a");
5004         } else {
5005                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5006                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5007         }
5008         /* wait for multiplication to finish */
5009         lbl = newiTempLabel(NULL);
5010         emitcode("","!tlabeldef", lbl->key+100);
5011         emitcode("mov","a,mcnt1");
5012         emitcode("anl","a,#!constbyte",0x80);
5013         emitcode("jnz","!tlabel",lbl->key+100);
5014
5015         freeAsmop (left, NULL, ic, TRUE);
5016         freeAsmop (right, NULL, ic,TRUE);
5017         aopOp(result, ic, TRUE, FALSE);
5018
5019         /* if unsigned then simple */
5020         if (umult) {
5021                 emitcode ("mov","a,ma");
5022                 if (AOP_SIZE(result) >= 4) aopPut(AOP(result),"a",3);
5023                 emitcode ("mov","a,ma");
5024                 if (AOP_SIZE(result) >= 3) aopPut(AOP(result),"a",2);
5025                 aopPut(AOP(result),"ma",1);
5026                 aopPut(AOP(result),"ma",0);
5027         } else {
5028                 emitcode("push","ma");
5029                 emitcode("push","ma");
5030                 emitcode("push","ma");
5031                 MOVA("ma");
5032                 /* negate result if needed */
5033                 lbl = newiTempLabel(NULL);
5034                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5035                 emitcode("cpl","a");
5036                 emitcode("add","a,#1");
5037                 emitcode("","!tlabeldef", lbl->key+100);
5038                 if (AOP_TYPE(result) == AOP_ACC)
5039                 {
5040                     D(emitcode(";", "ACC special case."););
5041                     /* We know result is the only live aop, and
5042                      * it's obviously not a DPTR2, so AP is available.
5043                      */
5044                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5045                 }
5046                 else
5047                 {
5048                     aopPut(AOP(result),"a",0);
5049                 }
5050
5051                 emitcode("pop","acc");
5052                 lbl = newiTempLabel(NULL);
5053                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5054                 emitcode("cpl","a");
5055                 emitcode("addc","a,#0");
5056                 emitcode("","!tlabeldef", lbl->key+100);
5057                 aopPut(AOP(result),"a",1);
5058                 emitcode("pop","acc");
5059                 if (AOP_SIZE(result) >= 3) {
5060                         lbl = newiTempLabel(NULL);
5061                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5062                         emitcode("cpl","a");
5063                         emitcode("addc","a,#0");
5064                         emitcode("","!tlabeldef", lbl->key+100);
5065                         aopPut(AOP(result),"a",2);
5066                 }
5067                 emitcode("pop","acc");
5068                 if (AOP_SIZE(result) >= 4) {
5069                         lbl = newiTempLabel(NULL);
5070                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5071                         emitcode("cpl","a");
5072                         emitcode("addc","a,#0");
5073                         emitcode("","!tlabeldef", lbl->key+100);
5074                         aopPut(AOP(result),"a",3);
5075                 }
5076                 if (AOP_TYPE(result) == AOP_ACC)
5077                 {
5078                     /* We stashed the result away above. */
5079                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5080                 }
5081
5082         }
5083         freeAsmop (result, NULL, ic, TRUE);
5084
5085         /* restore EA bit in F1 */
5086         lbl = newiTempLabel(NULL);
5087         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5088         emitcode ("setb","EA");
5089         emitcode("","!tlabeldef",lbl->key+100);
5090         return ;
5091 }
5092
5093 /*-----------------------------------------------------------------*/
5094 /* genMult - generates code for multiplication                     */
5095 /*-----------------------------------------------------------------*/
5096 static void
5097 genMult (iCode * ic)
5098 {
5099   operand *left = IC_LEFT (ic);
5100   operand *right = IC_RIGHT (ic);
5101   operand *result = IC_RESULT (ic);
5102
5103   D (emitcode (";", "genMult "););
5104
5105   /* assign the amsops */
5106   AOP_OP_2 (ic);
5107
5108   /* special cases first */
5109   /* both are bits */
5110   if (AOP_TYPE (left) == AOP_CRY &&
5111       AOP_TYPE (right) == AOP_CRY)
5112     {
5113       genMultbits (left, right, result, ic);
5114       goto release;
5115     }
5116
5117   /* if both are of size == 1 */
5118   if (AOP_SIZE (left) == 1 &&
5119       AOP_SIZE (right) == 1)
5120     {
5121       genMultOneByte (left, right, result, ic);
5122       goto release;
5123     }
5124
5125   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5126           /* use the ds390 ARITHMETIC accel UNIT */
5127           genMultTwoByte (left, right, result, ic);
5128           return ;
5129   }
5130   /* should have been converted to function call */
5131   assert (0);
5132
5133 release:
5134   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5135   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5136   freeAsmop (result, NULL, ic, TRUE);
5137 }
5138
5139 /*-----------------------------------------------------------------*/
5140 /* genDivbits :- division of bits                                  */
5141 /*-----------------------------------------------------------------*/
5142 static void
5143 genDivbits (operand * left,
5144             operand * right,
5145             operand * result,
5146             iCode   * ic)
5147 {
5148
5149   char *l;
5150
5151   /* the result must be bit */
5152   LOAD_AB_FOR_DIV (left, right, l);
5153   emitcode ("div", "ab");
5154   emitcode ("rrc", "a");
5155   aopOp(result, ic, TRUE, FALSE);
5156
5157   aopPut (AOP (result), "c", 0);
5158 }
5159
5160 /*-----------------------------------------------------------------*/
5161 /* genDivOneByte : 8 bit division                                  */
5162 /*-----------------------------------------------------------------*/
5163 static void
5164 genDivOneByte (operand * left,
5165                operand * right,
5166                operand * result,
5167                iCode   * ic)
5168 {
5169   bool lUnsigned, rUnsigned;
5170   bool runtimeSign, compiletimeSign;
5171   char *l;
5172   symbol *lbl;
5173   int size, offset;
5174
5175   offset = 1;
5176   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5177   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5178
5179   /* signed or unsigned */
5180   if (lUnsigned && rUnsigned)
5181     {
5182       /* unsigned is easy */
5183       LOAD_AB_FOR_DIV (left, right, l);
5184       emitcode ("div", "ab");
5185
5186       _G.accInUse++;
5187       aopOp (result, ic, TRUE, FALSE);
5188       aopPut (AOP (result), "a", 0);
5189       _G.accInUse--;
5190
5191       size = AOP_SIZE (result) - 1;
5192
5193       while (size--)
5194         aopPut (AOP (result), zero, offset++);
5195       return;
5196     }
5197
5198   /* signed is a little bit more difficult */
5199
5200   /* now sign adjust for both left & right */
5201
5202   /* let's see what's needed: */
5203   /* apply negative sign during runtime */
5204   runtimeSign = FALSE;
5205   /* negative sign from literals */
5206   compiletimeSign = FALSE;
5207
5208   if (!lUnsigned)
5209     {
5210       if (AOP_TYPE(left) == AOP_LIT)
5211         {
5212           /* signed literal */
5213           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5214           if (val < 0)
5215             compiletimeSign = TRUE;
5216         }
5217       else
5218         /* signed but not literal */
5219         runtimeSign = TRUE;
5220     }
5221
5222   if (!rUnsigned)
5223     {
5224       if (AOP_TYPE(right) == AOP_LIT)
5225         {
5226           /* signed literal */
5227           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5228           if (val < 0)
5229             compiletimeSign ^= TRUE;
5230         }
5231       else
5232         /* signed but not literal */
5233         runtimeSign = TRUE;
5234     }
5235
5236   /* initialize F0, which stores the runtime sign */
5237   if (runtimeSign)
5238     {
5239       if (compiletimeSign)
5240         emitcode ("setb", "F0"); /* set sign flag */
5241       else
5242         emitcode ("clr", "F0"); /* reset sign flag */
5243     }
5244
5245   /* save the signs of the operands */
5246   if (AOP_TYPE(right) == AOP_LIT)
5247     {
5248       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5249
5250       if (!rUnsigned && val < 0)
5251         emitcode ("mov", "b,#0x%02x", -val);
5252       else
5253         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5254     }
5255   else /* ! literal */
5256     {
5257       if (rUnsigned)
5258         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5259       else
5260         {
5261           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5262           lbl = newiTempLabel (NULL);
5263           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5264           emitcode ("cpl", "F0"); /* complement sign flag */
5265           emitcode ("cpl", "a");  /* 2's complement */
5266           emitcode ("inc", "a");
5267           emitcode ("", "!tlabeldef", lbl->key + 100);
5268           emitcode ("mov", "b,a");
5269         }
5270     }
5271
5272   if (AOP_TYPE(left) == AOP_LIT)
5273     {
5274       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5275
5276       if (!lUnsigned && val < 0)
5277         emitcode ("mov", "a,#0x%02x", -val);
5278       else
5279         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5280     }
5281   else /* ! literal */
5282     {
5283       if (lUnsigned)
5284         emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5285       else
5286         {
5287           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5288           lbl = newiTempLabel (NULL);
5289           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5290           emitcode ("cpl", "F0"); /* complement sign flag */
5291           emitcode ("cpl", "a");  /* 2's complement */
5292           emitcode ("inc", "a");
5293           emitcode ("", "!tlabeldef", lbl->key + 100);
5294         }
5295     }
5296
5297   /* now the division */
5298   emitcode ("nop", "; workaround for DS80C390 div bug.");
5299   emitcode ("div", "ab");
5300
5301   if (runtimeSign || compiletimeSign)
5302     {
5303       lbl = newiTempLabel (NULL);
5304       if (runtimeSign)
5305         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5306       emitcode ("cpl", "a"); /* lsb 2's complement */
5307       emitcode ("inc", "a");
5308       emitcode ("", "!tlabeldef", lbl->key + 100);
5309
5310       _G.accInUse++;     _G.bInUse++;
5311       aopOp (result, ic, TRUE, FALSE);
5312       size = AOP_SIZE (result) - 1;
5313
5314       if (size > 0)
5315         {
5316           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5317              then the result will be in b, a */
5318           emitcode ("mov", "b,a"); /* 1 */
5319           /* msb is 0x00 or 0xff depending on the sign */
5320           if (runtimeSign)
5321             {
5322               emitcode ("mov",  "c,F0");
5323               emitcode ("subb", "a,acc");
5324               emitcode ("xch",  "a,b"); /* 2 */
5325               while (size--)
5326                 aopPut (AOP (result), "b", offset++); /* write msb's */
5327             }
5328           else /* compiletimeSign */
5329             while (size--)
5330               aopPut (AOP (result), "#0xff", offset++); /* write msb's */
5331         }
5332       aopPut (AOP (result), "a", 0); /* 3: write lsb */
5333     }
5334   else
5335     {
5336       _G.accInUse++;     _G.bInUse++;
5337       aopOp(result, ic, TRUE, FALSE);
5338       size = AOP_SIZE (result) - 1;
5339
5340       aopPut (AOP (result), "a", 0);
5341       while (size--)
5342         aopPut (AOP (result), zero, offset++);
5343     }
5344   _G.accInUse--;     _G.bInUse--;
5345
5346 }
5347
5348 /*-----------------------------------------------------------------*/
5349 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5350 /*-----------------------------------------------------------------*/
5351 static void genDivTwoByte (operand *left, operand *right,
5352                             operand *result, iCode *ic)
5353 {
5354         sym_link *retype = getSpec(operandType(right));
5355         sym_link *letype = getSpec(operandType(left));
5356         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5357         symbol *lbl;
5358
5359         /* save EA bit in F1 */
5360         lbl = newiTempLabel(NULL);
5361         emitcode ("setb","F1");
5362         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5363         emitcode ("clr","F1");
5364         emitcode("","!tlabeldef",lbl->key+100);
5365
5366         /* load up MA with left */
5367         if (!umult) {
5368                 emitcode("clr","F0");
5369                 lbl = newiTempLabel(NULL);
5370                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5371                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5372                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5373                 emitcode ("xch", "a,b");
5374                 emitcode ("cpl","a");
5375                 emitcode ("add", "a,#1");
5376                 emitcode ("xch", "a,b");
5377                 emitcode ("cpl", "a"); // msb
5378                 emitcode ("addc","a,#0");
5379                 emitcode ("setb","F0");
5380                 emitcode ("","!tlabeldef",lbl->key+100);
5381                 emitcode ("mov","ma,b");
5382                 emitcode ("mov","ma,a");
5383         } else {
5384                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5385                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5386         }
5387
5388         /* load up MB with right */
5389         if (!umult) {
5390                 if (AOP_TYPE(right) == AOP_LIT) {
5391                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5392                         if (val < 0) {
5393                                 lbl = newiTempLabel(NULL);
5394                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5395                                 emitcode("setb","F0");
5396                                 emitcode ("","!tlabeldef",lbl->key+100);
5397                                 val = -val;
5398                         }
5399                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5400                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5401                 } else {
5402                         lbl = newiTempLabel(NULL);
5403                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5404                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5405                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5406                         emitcode ("xch", "a,b");
5407                         emitcode ("cpl","a");
5408                         emitcode ("add", "a,#1");
5409                         emitcode ("xch", "a,b");
5410                         emitcode ("cpl", "a"); // msb
5411                         emitcode ("addc", "a,#0");
5412                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5413                         emitcode ("setb","F0");
5414                         emitcode ("","!tlabeldef",lbl->key+100);
5415                         emitcode ("mov","mb,b");
5416                         emitcode ("mov","mb,a");
5417                 }
5418         } else {
5419                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5420                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5421         }
5422
5423         /* wait for multiplication to finish */
5424         lbl = newiTempLabel(NULL);
5425         emitcode("","!tlabeldef", lbl->key+100);
5426         emitcode("mov","a,mcnt1");
5427         emitcode("anl","a,#!constbyte",0x80);
5428         emitcode("jnz","!tlabel",lbl->key+100);
5429
5430         freeAsmop (left, NULL, ic, TRUE);
5431         freeAsmop (right, NULL, ic,TRUE);
5432         aopOp(result, ic, TRUE, FALSE);
5433
5434         /* if unsigned then simple */
5435         if (umult) {
5436                 aopPut(AOP(result),"ma",1);
5437                 aopPut(AOP(result),"ma",0);
5438         } else {
5439                 emitcode("push","ma");
5440                 MOVA("ma");
5441                 /* negate result if needed */
5442                 lbl = newiTempLabel(NULL);
5443                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5444                 emitcode("cpl","a");
5445                 emitcode("add","a,#1");
5446                 emitcode("","!tlabeldef", lbl->key+100);
5447                 aopPut(AOP(result),"a",0);
5448                 emitcode("pop","acc");
5449                 lbl = newiTempLabel(NULL);
5450                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5451                 emitcode("cpl","a");
5452                 emitcode("addc","a,#0");
5453                 emitcode("","!tlabeldef", lbl->key+100);
5454                 aopPut(AOP(result),"a",1);
5455         }
5456         freeAsmop (result, NULL, ic, TRUE);
5457         /* restore EA bit in F1 */
5458         lbl = newiTempLabel(NULL);
5459         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5460         emitcode ("setb","EA");
5461         emitcode("","!tlabeldef",lbl->key+100);
5462         return ;
5463 }
5464
5465 /*-----------------------------------------------------------------*/
5466 /* genDiv - generates code for division                            */
5467 /*-----------------------------------------------------------------*/
5468 static void
5469 genDiv (iCode * ic)
5470 {
5471   operand *left = IC_LEFT (ic);
5472   operand *right = IC_RIGHT (ic);
5473   operand *result = IC_RESULT (ic);
5474
5475   D (emitcode (";", "genDiv "););
5476
5477   /* assign the amsops */
5478   AOP_OP_2 (ic);
5479
5480   /* special cases first */
5481   /* both are bits */
5482   if (AOP_TYPE (left) == AOP_CRY &&
5483       AOP_TYPE (right) == AOP_CRY)
5484     {
5485       genDivbits (left, right, result, ic);
5486       goto release;
5487     }
5488
5489   /* if both are of size == 1 */
5490   if (AOP_SIZE (left) == 1 &&
5491       AOP_SIZE (right) == 1)
5492     {
5493       genDivOneByte (left, right, result, ic);
5494       goto release;
5495     }
5496
5497   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5498           /* use the ds390 ARITHMETIC accel UNIT */
5499           genDivTwoByte (left, right, result, ic);
5500           return ;
5501   }
5502   /* should have been converted to function call */
5503   assert (0);
5504 release:
5505   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5506   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5507   freeAsmop (result, NULL, ic, TRUE);
5508 }
5509
5510 /*-----------------------------------------------------------------*/
5511 /* genModbits :- modulus of bits                                   */
5512 /*-----------------------------------------------------------------*/
5513 static void
5514 genModbits (operand * left,
5515             operand * right,
5516             operand * result,
5517             iCode   * ic)
5518 {
5519
5520   char *l;
5521
5522   /* the result must be bit */
5523   LOAD_AB_FOR_DIV (left, right, l);
5524   emitcode ("div", "ab");
5525   emitcode ("mov", "a,b");
5526   emitcode ("rrc", "a");
5527   aopOp(result, ic, TRUE, FALSE);
5528   aopPut (AOP (result), "c", 0);
5529 }
5530
5531 /*-----------------------------------------------------------------*/
5532 /* genModOneByte : 8 bit modulus                                   */
5533 /*-----------------------------------------------------------------*/
5534 static void
5535 genModOneByte (operand * left,
5536                operand * right,
5537                operand * result,
5538                iCode   * ic)
5539 {
5540   bool lUnsigned, rUnsigned;
5541   bool runtimeSign, compiletimeSign;
5542   char *l;
5543   symbol *lbl;
5544   int size, offset;
5545
5546   offset = 1;
5547   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5548   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5549
5550   /* signed or unsigned */
5551   if (lUnsigned && rUnsigned)
5552     {
5553       /* unsigned is easy */
5554       LOAD_AB_FOR_DIV (left, right, l);
5555       emitcode ("div", "ab");
5556       aopOp (result, ic, TRUE, FALSE);
5557       aopPut (AOP (result), "b", 0);
5558
5559       for (size = AOP_SIZE (result) - 1; size--;)
5560         aopPut (AOP (result), zero, offset++);
5561       return;
5562     }
5563
5564   /* signed is a little bit more difficult */
5565
5566   /* now sign adjust for both left & right */
5567
5568   /* modulus: sign of the right operand has no influence on the result! */
5569   if (AOP_TYPE(right) == AOP_LIT)
5570     {
5571       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5572
5573       if (!rUnsigned && val < 0)
5574         emitcode ("mov", "b,#0x%02x", -val);
5575       else
5576         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5577     }
5578   else /* ! literal */
5579     {
5580       if (rUnsigned)
5581         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5582       else
5583         {
5584           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5585           lbl = newiTempLabel (NULL);
5586           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5587           emitcode ("cpl", "a");  /* 2's complement */
5588           emitcode ("inc", "a");
5589           emitcode ("", "!tlabeldef", lbl->key + 100);
5590           emitcode ("mov", "b,a");
5591         }
5592     }
5593
5594   /* let's see what's needed: */
5595   /* apply negative sign during runtime */
5596   runtimeSign = FALSE;
5597   /* negative sign from literals */
5598   compiletimeSign = FALSE;
5599
5600   /* sign adjust left side */
5601   if (AOP_TYPE(left) == AOP_LIT)
5602     {
5603       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5604
5605       if (!lUnsigned && val < 0)
5606         {
5607           compiletimeSign = TRUE; /* set sign flag */
5608           emitcode ("mov", "a,#0x%02x", -val);
5609         }
5610       else
5611         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5612     }
5613   else /* ! literal */
5614     {
5615       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5616
5617       if (!lUnsigned)
5618         {
5619           runtimeSign = TRUE;
5620           emitcode ("clr", "F0"); /* clear sign flag */
5621
5622           lbl = newiTempLabel (NULL);
5623           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5624           emitcode ("setb", "F0"); /* set sign flag */
5625           emitcode ("cpl", "a");   /* 2's complement */
5626           emitcode ("inc", "a");
5627           emitcode ("", "!tlabeldef", lbl->key + 100);
5628         }
5629     }
5630
5631   /* now the modulus */
5632   emitcode ("nop", "; workaround for DS80C390 div bug.");
5633   emitcode ("div", "ab");
5634
5635   if (runtimeSign || compiletimeSign)
5636     {
5637       emitcode ("mov", "a,b");
5638       lbl = newiTempLabel (NULL);
5639       if (runtimeSign)
5640         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5641       emitcode ("cpl", "a"); /* lsb 2's complement */
5642       emitcode ("inc", "a");
5643       emitcode ("", "!tlabeldef", lbl->key + 100);
5644
5645       _G.accInUse++;     _G.bInUse++;
5646       aopOp (result, ic, TRUE, FALSE);
5647       size = AOP_SIZE (result) - 1;
5648
5649       if (size > 0)
5650         {
5651           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5652              then the result will be in b, a */
5653           emitcode ("mov", "b,a"); /* 1 */
5654           /* msb is 0x00 or 0xff depending on the sign */
5655           if (runtimeSign)
5656             {
5657               emitcode ("mov",  "c,F0");
5658               emitcode ("subb", "a,acc");
5659               emitcode ("xch",  "a,b"); /* 2 */
5660               while (size--)
5661                 aopPut (AOP (result), "b", offset++); /* write msb's */
5662             }
5663           else /* compiletimeSign */
5664             while (size--)
5665               aopPut (AOP (result), "#0xff", offset++); /* write msb's */
5666         }
5667       aopPut (AOP (result), "a", 0); /* 3: write lsb */
5668     }
5669   else
5670     {
5671       _G.accInUse++;     _G.bInUse++;
5672       aopOp(result, ic, TRUE, FALSE);
5673       size = AOP_SIZE (result) - 1;
5674
5675       aopPut (AOP (result), "b", 0);
5676       while (size--)
5677         aopPut (AOP (result), zero, offset++);
5678     }
5679   _G.accInUse--;     _G.bInUse--;
5680
5681 }
5682
5683 /*-----------------------------------------------------------------*/
5684 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
5685 /*-----------------------------------------------------------------*/
5686 static void genModTwoByte (operand *left, operand *right,
5687                             operand *result, iCode *ic)
5688 {
5689         sym_link *retype = getSpec(operandType(right));
5690         sym_link *letype = getSpec(operandType(left));
5691         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5692         symbol *lbl;
5693
5694         /* load up MA with left */
5695         /* save EA bit in F1 */
5696         lbl = newiTempLabel(NULL);
5697         emitcode ("setb","F1");
5698         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5699         emitcode ("clr","F1");
5700         emitcode("","!tlabeldef",lbl->key+100);
5701
5702         if (!umult) {
5703                 lbl = newiTempLabel(NULL);
5704                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5705                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5706                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5707                 emitcode ("xch", "a,b");
5708                 emitcode ("cpl","a");
5709                 emitcode ("add", "a,#1");
5710                 emitcode ("xch", "a,b");
5711                 emitcode ("cpl", "a"); // msb
5712                 emitcode ("addc","a,#0");
5713                 emitcode ("","!tlabeldef",lbl->key+100);
5714                 emitcode ("mov","ma,b");
5715                 emitcode ("mov","ma,a");
5716         } else {
5717                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5718                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5719         }
5720
5721         /* load up MB with right */
5722         if (!umult) {
5723                 if (AOP_TYPE(right) == AOP_LIT) {
5724                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5725                         if (val < 0) {
5726                                 val = -val;
5727                         }
5728                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5729                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5730                 } else {
5731                         lbl = newiTempLabel(NULL);
5732                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5733                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5734                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5735                         emitcode ("xch", "a,b");
5736                         emitcode ("cpl","a");
5737                         emitcode ("add", "a,#1");
5738                         emitcode ("xch", "a,b");
5739                         emitcode ("cpl", "a"); // msb
5740                         emitcode ("addc", "a,#0");
5741                         emitcode ("","!tlabeldef",lbl->key+100);
5742                         emitcode ("mov","mb,b");
5743                         emitcode ("mov","mb,a");
5744                 }
5745         } else {
5746                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5747                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5748         }
5749
5750         /* wait for multiplication to finish */
5751         lbl = newiTempLabel(NULL);
5752         emitcode("","!tlabeldef", lbl->key+100);
5753         emitcode("mov","a,mcnt1");
5754         emitcode("anl","a,#!constbyte",0x80);
5755         emitcode("jnz","!tlabel",lbl->key+100);
5756
5757         freeAsmop (left, NULL, ic, TRUE);
5758         freeAsmop (right, NULL, ic,TRUE);
5759         aopOp(result, ic, TRUE, FALSE);
5760
5761         aopPut(AOP(result),"mb",1);
5762         aopPut(AOP(result),"mb",0);
5763         freeAsmop (result, NULL, ic, TRUE);
5764
5765         /* restore EA bit in F1 */
5766         lbl = newiTempLabel(NULL);
5767         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5768         emitcode ("setb","EA");
5769         emitcode("","!tlabeldef",lbl->key+100);
5770         return ;
5771 }
5772
5773 /*-----------------------------------------------------------------*/
5774 /* genMod - generates code for division                            */
5775 /*-----------------------------------------------------------------*/
5776 static void
5777 genMod (iCode * ic)
5778 {
5779   operand *left = IC_LEFT (ic);
5780   operand *right = IC_RIGHT (ic);
5781   operand *result = IC_RESULT (ic);
5782
5783   D (emitcode (";", "genMod "); );
5784
5785   /* assign the amsops */
5786   AOP_OP_2 (ic);
5787
5788   /* special cases first */
5789   /* both are bits */
5790   if (AOP_TYPE (left) == AOP_CRY &&
5791       AOP_TYPE (right) == AOP_CRY)
5792     {
5793       genModbits (left, right, result, ic);
5794       goto release;
5795     }
5796
5797   /* if both are of size == 1 */
5798   if (AOP_SIZE (left) == 1 &&
5799       AOP_SIZE (right) == 1)
5800     {
5801       genModOneByte (left, right, result, ic);
5802       goto release;
5803     }
5804
5805   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5806           /* use the ds390 ARITHMETIC accel UNIT */
5807           genModTwoByte (left, right, result, ic);
5808           return ;
5809   }
5810
5811   /* should have been converted to function call */
5812   assert (0);
5813
5814 release:
5815   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5816   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5817   freeAsmop (result, NULL, ic, TRUE);
5818 }
5819
5820 /*-----------------------------------------------------------------*/
5821 /* genIfxJump :- will create a jump depending on the ifx           */
5822 /*-----------------------------------------------------------------*/
5823 static void
5824 genIfxJump (iCode * ic, char *jval)
5825 {
5826   symbol *jlbl;
5827   symbol *tlbl = newiTempLabel (NULL);
5828   char *inst;
5829
5830   D (emitcode (";", "genIfxJump"););
5831
5832   /* if true label then we jump if condition
5833      supplied is true */
5834   if (IC_TRUE (ic))
5835     {
5836       jlbl = IC_TRUE (ic);
5837       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5838                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5839     }
5840   else
5841     {
5842       /* false label is present */
5843       jlbl = IC_FALSE (ic);
5844       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5845                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5846     }
5847   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5848     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
5849   else
5850     emitcode (inst, "!tlabel", tlbl->key + 100);
5851   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
5852   emitcode ("", "!tlabeldef", tlbl->key + 100);
5853
5854   /* mark the icode as generated */
5855   ic->generated = 1;
5856 }
5857
5858 /*-----------------------------------------------------------------*/
5859 /* genCmp :- greater or less than comparison                       */
5860 /*-----------------------------------------------------------------*/
5861 static void
5862 genCmp (operand * left, operand * right,
5863         iCode * ic, iCode * ifx, int sign)
5864 {
5865   int size, offset = 0;
5866   unsigned long lit = 0L;
5867   operand *result;
5868
5869   D (emitcode (";", "genCmp"););
5870
5871   result = IC_RESULT (ic);
5872
5873   /* if left & right are bit variables */
5874   if (AOP_TYPE (left) == AOP_CRY &&
5875       AOP_TYPE (right) == AOP_CRY)
5876     {
5877       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5878       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5879     }
5880   else
5881     {
5882       /* subtract right from left if at the
5883          end the carry flag is set then we know that
5884          left is greater than right */
5885       size = max (AOP_SIZE (left), AOP_SIZE (right));
5886
5887       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5888       if ((size == 1) && !sign
5889           && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
5890         {
5891           symbol *lbl = newiTempLabel (NULL);
5892           emitcode ("cjne", "%s,%s,!tlabel",
5893                     aopGet (AOP (left), offset, FALSE, FALSE, NULL),
5894                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
5895                     lbl->key + 100);
5896           emitcode ("", "!tlabeldef", lbl->key + 100);
5897         }
5898       else
5899         {
5900           if (AOP_TYPE (right) == AOP_LIT)
5901             {
5902               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5903               /* optimize if(x < 0) or if(x >= 0) */
5904               if (lit == 0L)
5905                 {
5906                   if (!sign)
5907                     {
5908                       CLRC;
5909                     }
5910                   else
5911                     {
5912                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
5913
5914                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5915                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5916
5917                       aopOp (result, ic, FALSE, FALSE);
5918
5919                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5920                         {
5921                           freeAsmop (result, NULL, ic, TRUE);
5922                           genIfxJump (ifx, "acc.7");
5923                           return;
5924                         }
5925                       else
5926                         {
5927                           emitcode ("rlc", "a");
5928                         }
5929                       goto release_freedLR;
5930                     }
5931                   goto release;
5932                 }
5933             }
5934           CLRC;
5935           while (size--)
5936             {
5937               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
5938               MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5939               // emitcode (";", "genCmp #2");
5940               if (sign && (size == 0))
5941                 {
5942                   // emitcode (";", "genCmp #3");
5943                   emitcode ("xrl", "a,#!constbyte",0x80);
5944                   if (AOP_TYPE (right) == AOP_LIT)
5945                     {
5946                       unsigned long lit = (unsigned long)
5947                       floatFromVal (AOP (right)->aopu.aop_lit);
5948                       // emitcode (";", "genCmp #3.1");
5949                       emitcode ("subb", "a,#!constbyte",
5950                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5951                     }
5952                   else
5953                     {
5954                       // emitcode (";", "genCmp #3.2");
5955                       saveAccWarn = 0;
5956                       MOVB(aopGet (AOP (right), offset++, FALSE, FALSE, "b"));
5957                       saveAccWarn = DEFAULT_ACC_WARNING;
5958                       emitcode ("xrl", "b,#!constbyte",0x80);
5959                       emitcode ("subb", "a,b");
5960                     }
5961                 }
5962               else
5963                 {
5964                   const char *s;
5965
5966                   // emitcode (";", "genCmp #4");
5967                   saveAccWarn = 0;
5968                   s = aopGet (AOP (right), offset++, FALSE, FALSE, "b");
5969                   saveAccWarn = DEFAULT_ACC_WARNING;
5970
5971                   emitcode ("subb", "a,%s", s);
5972                 }
5973             }
5974         }
5975     }
5976
5977 release:
5978 /* Don't need the left & right operands any more; do need the result. */
5979   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5980   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5981
5982   aopOp (result, ic, FALSE, FALSE);
5983
5984 release_freedLR:
5985
5986   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5987     {
5988       outBitC (result);
5989     }
5990   else
5991     {
5992       /* if the result is used in the next
5993          ifx conditional branch then generate
5994          code a little differently */
5995       if (ifx)
5996         {
5997           genIfxJump (ifx, "c");
5998         }
5999       else
6000         {
6001           outBitC (result);
6002         }
6003       /* leave the result in acc */
6004     }
6005   freeAsmop (result, NULL, ic, TRUE);
6006 }
6007
6008 /*-----------------------------------------------------------------*/
6009 /* genCmpGt :- greater than comparison                             */
6010 /*-----------------------------------------------------------------*/
6011 static void
6012 genCmpGt (iCode * ic, iCode * ifx)
6013 {
6014   operand *left, *right;
6015   sym_link *letype, *retype;
6016   int sign;
6017
6018   D (emitcode (";", "genCmpGt ");
6019     );
6020
6021   left = IC_LEFT (ic);
6022   right = IC_RIGHT (ic);
6023
6024   letype = getSpec (operandType (left));
6025   retype = getSpec (operandType (right));
6026   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6027
6028   /* assign the left & right amsops */
6029   AOP_OP_2 (ic);
6030
6031   genCmp (right, left, ic, ifx, sign);
6032 }
6033
6034 /*-----------------------------------------------------------------*/
6035 /* genCmpLt - less than comparisons                                */
6036 /*-----------------------------------------------------------------*/
6037 static void
6038 genCmpLt (iCode * ic, iCode * ifx)
6039 {
6040   operand *left, *right;
6041   sym_link *letype, *retype;
6042   int sign;
6043
6044   D (emitcode (";", "genCmpLt "););
6045
6046   left = IC_LEFT (ic);
6047   right = IC_RIGHT (ic);
6048
6049   letype = getSpec (operandType (left));
6050   retype = getSpec (operandType (right));
6051   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6052
6053   /* assign the left & right amsops */
6054   AOP_OP_2 (ic);
6055
6056   genCmp (left, right, ic, ifx, sign);
6057 }
6058
6059 /*-----------------------------------------------------------------*/
6060 /* gencjneshort - compare and jump if not equal                    */
6061 /*-----------------------------------------------------------------*/
6062 static void
6063 gencjneshort (operand * left, operand * right, symbol * lbl)
6064 {
6065   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6066   int offset = 0;
6067   unsigned long lit = 0L;
6068
6069   D (emitcode (";", "gencjneshort");
6070     );
6071
6072   /* if the left side is a literal or
6073      if the right is in a pointer register and left
6074      is not */
6075   if ((AOP_TYPE (left) == AOP_LIT) ||
6076       (AOP_TYPE (left) == AOP_IMMD) ||
6077       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6078     {
6079       operand *t = right;
6080       right = left;
6081       left = t;
6082     }
6083
6084   if (AOP_TYPE (right) == AOP_LIT)
6085     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6086
6087   if (opIsGptr (left) || opIsGptr (right))
6088     {
6089       /* We are comparing a generic pointer to something.
6090        * Exclude the generic type byte from the comparison.
6091        */
6092       size--;
6093       D (emitcode (";", "cjneshort: generic ptr special case."););
6094     }
6095
6096
6097   /* if the right side is a literal then anything goes */
6098   if (AOP_TYPE (right) == AOP_LIT &&
6099       AOP_TYPE (left) != AOP_DIR)
6100     {
6101       while (size--)
6102         {
6103           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6104           emitcode ("cjne", "a,%s,!tlabel",
6105                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
6106                     lbl->key + 100);
6107           offset++;
6108         }
6109     }
6110
6111   /* if the right side is in a register or in direct space or
6112      if the left is a pointer register & right is not */
6113   else if (AOP_TYPE (right) == AOP_REG ||
6114            AOP_TYPE (right) == AOP_DIR ||
6115            AOP_TYPE (right) == AOP_LIT ||
6116            AOP_TYPE (right) == AOP_IMMD ||
6117            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6118            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6119     {
6120       while (size--)
6121         {
6122           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6123           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6124               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6125             emitcode ("jnz", "!tlabel", lbl->key + 100);
6126           else
6127             emitcode ("cjne", "a,%s,!tlabel",
6128                       aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG),
6129                       lbl->key + 100);
6130           offset++;
6131         }
6132     }
6133   else
6134     {
6135       /* right is a pointer reg need both a & b */
6136       while (size--)
6137         {
6138           MOVB (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6139           MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6140           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6141           offset++;
6142         }
6143     }
6144 }
6145
6146 /*-----------------------------------------------------------------*/
6147 /* gencjne - compare and jump if not equal                         */
6148 /*-----------------------------------------------------------------*/
6149 static void
6150 gencjne (operand * left, operand * right, symbol * lbl)
6151 {
6152   symbol *tlbl = newiTempLabel (NULL);
6153
6154   D (emitcode (";", "gencjne");
6155     );
6156
6157   gencjneshort (left, right, lbl);
6158
6159   emitcode ("mov", "a,%s", one);
6160   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6161   emitcode ("", "!tlabeldef", lbl->key + 100);
6162   emitcode ("clr", "a");
6163   emitcode ("", "!tlabeldef", tlbl->key + 100);
6164 }
6165
6166 /*-----------------------------------------------------------------*/
6167 /* genCmpEq - generates code for equal to                          */
6168 /*-----------------------------------------------------------------*/
6169 static void
6170 genCmpEq (iCode * ic, iCode * ifx)
6171 {
6172   operand *left, *right, *result;
6173
6174   D (emitcode (";", "genCmpEq ");
6175     );
6176
6177   AOP_OP_2 (ic);
6178   AOP_SET_LOCALS (ic);
6179
6180   /* if literal, literal on the right or
6181      if the right is in a pointer register and left
6182      is not */
6183   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6184       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6185     {
6186       operand *t = IC_RIGHT (ic);
6187       IC_RIGHT (ic) = IC_LEFT (ic);
6188       IC_LEFT (ic) = t;
6189     }
6190
6191   if (ifx &&                    /* !AOP_SIZE(result) */
6192       OP_SYMBOL (result) &&
6193       OP_SYMBOL (result)->regType == REG_CND)
6194     {
6195       symbol *tlbl;
6196       /* if they are both bit variables */
6197       if (AOP_TYPE (left) == AOP_CRY &&
6198           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6199         {
6200           if (AOP_TYPE (right) == AOP_LIT)
6201             {
6202               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6203               if (lit == 0L)
6204                 {
6205                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6206                   emitcode ("cpl", "c");
6207                 }
6208               else if (lit == 1L)
6209                 {
6210                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6211                 }
6212               else
6213                 {
6214                   emitcode ("clr", "c");
6215                 }
6216               /* AOP_TYPE(right) == AOP_CRY */
6217             }
6218           else
6219             {
6220               symbol *lbl = newiTempLabel (NULL);
6221               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6222               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6223               emitcode ("cpl", "c");
6224               emitcode ("", "!tlabeldef", (lbl->key + 100));
6225             }
6226           /* if true label then we jump if condition
6227              supplied is true */
6228           tlbl = newiTempLabel (NULL);
6229           if (IC_TRUE (ifx))
6230             {
6231               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6232               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6233             }
6234           else
6235             {
6236               emitcode ("jc", "!tlabel", tlbl->key + 100);
6237               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6238             }
6239           emitcode ("", "!tlabeldef", tlbl->key + 100);
6240         }
6241       else
6242         {
6243           tlbl = newiTempLabel (NULL);
6244           gencjneshort (left, right, tlbl);
6245           if (IC_TRUE (ifx))
6246             {
6247               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6248               emitcode ("", "!tlabeldef", tlbl->key + 100);
6249             }
6250           else
6251             {
6252               symbol *lbl = newiTempLabel (NULL);
6253               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6254               emitcode ("", "!tlabeldef", tlbl->key + 100);
6255               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6256               emitcode ("", "!tlabeldef", lbl->key + 100);
6257             }
6258         }
6259       /* mark the icode as generated */
6260       ifx->generated = 1;
6261
6262       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6263       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6264       return;
6265     }
6266
6267   /* if they are both bit variables */
6268   if (AOP_TYPE (left) == AOP_CRY &&
6269       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6270     {
6271       if (AOP_TYPE (right) == AOP_LIT)
6272         {
6273           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6274           if (lit == 0L)
6275             {
6276               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6277               emitcode ("cpl", "c");
6278             }
6279           else if (lit == 1L)
6280             {
6281               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6282             }
6283           else
6284             {
6285               emitcode ("clr", "c");
6286             }
6287           /* AOP_TYPE(right) == AOP_CRY */
6288         }
6289       else
6290         {
6291           symbol *lbl = newiTempLabel (NULL);
6292           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6293           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6294           emitcode ("cpl", "c");
6295           emitcode ("", "!tlabeldef", (lbl->key + 100));
6296         }
6297
6298       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6299       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6300
6301       aopOp (result, ic, TRUE, FALSE);
6302
6303       /* c = 1 if egal */
6304       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6305         {
6306           outBitC (result);
6307           goto release;
6308         }
6309       if (ifx)
6310         {
6311           genIfxJump (ifx, "c");
6312           goto release;
6313         }
6314       /* if the result is used in an arithmetic operation
6315          then put the result in place */
6316       outBitC (result);
6317     }
6318   else
6319     {
6320       gencjne (left, right, newiTempLabel (NULL));
6321
6322       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6323       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6324
6325       aopOp (result, ic, TRUE, FALSE);
6326
6327       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6328         {
6329           aopPut (AOP (result), "a", 0);
6330           goto release;
6331         }
6332       if (ifx)
6333         {
6334           genIfxJump (ifx, "a");
6335           goto release;
6336         }
6337       /* if the result is used in an arithmetic operation
6338          then put the result in place */
6339       if (AOP_TYPE (result) != AOP_CRY)
6340         outAcc (result);
6341       /* leave the result in acc */
6342     }
6343
6344 release:
6345   freeAsmop (result, NULL, ic, TRUE);
6346 }
6347
6348 /*-----------------------------------------------------------------*/
6349 /* ifxForOp - returns the icode containing the ifx for operand     */
6350 /*-----------------------------------------------------------------*/
6351 static iCode *
6352 ifxForOp (operand * op, iCode * ic)
6353 {
6354   /* if true symbol then needs to be assigned */
6355   if (IS_TRUE_SYMOP (op))
6356     return NULL;
6357
6358   /* if this has register type condition and
6359      the next instruction is ifx with the same operand
6360      and live to of the operand is upto the ifx only then */
6361   if (ic->next &&
6362       ic->next->op == IFX &&
6363       IC_COND (ic->next)->key == op->key &&
6364       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6365     return ic->next;
6366
6367   return NULL;
6368 }
6369 /*-----------------------------------------------------------------*/
6370 /* hasInc - operand is incremented before any other use            */
6371 /*-----------------------------------------------------------------*/
6372 static iCode *
6373 hasInc (operand *op, iCode *ic, int osize)
6374 {
6375   sym_link *type = operandType(op);
6376   sym_link *retype = getSpec (type);
6377   iCode *lic = ic->next;
6378   int isize ;
6379
6380   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6381   if (!IS_SYMOP(op)) return NULL;
6382
6383   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6384   if (IS_AGGREGATE(type->next)) return NULL;
6385   if (osize != (isize = getSize(type->next))) return NULL;
6386
6387   while (lic) {
6388       /* if operand of the form op = op + <sizeof *op> */
6389       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6390           isOperandEqual(IC_RESULT(lic),op) &&
6391           isOperandLiteral(IC_RIGHT(lic)) &&
6392           operandLitValue(IC_RIGHT(lic)) == isize) {
6393           return lic;
6394       }
6395       /* if the operand used or deffed */
6396       if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
6397           return NULL;
6398       }
6399       /* if GOTO or IFX */
6400       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6401       lic = lic->next;
6402   }
6403   return NULL;
6404 }
6405
6406 /*-----------------------------------------------------------------*/
6407 /* genAndOp - for && operation                                     */
6408 /*-----------------------------------------------------------------*/
6409 static void
6410 genAndOp (iCode * ic)
6411 {
6412   operand *left, *right, *result;
6413   symbol *tlbl;
6414
6415   D (emitcode (";", "genAndOp "););
6416
6417   /* note here that && operations that are in an
6418      if statement are taken away by backPatchLabels
6419      only those used in arthmetic operations remain */
6420   AOP_OP_2 (ic);
6421   AOP_SET_LOCALS (ic);
6422
6423   /* if both are bit variables */
6424   if (AOP_TYPE (left) == AOP_CRY &&
6425       AOP_TYPE (right) == AOP_CRY)
6426     {
6427       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6428       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6429       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6430       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6431
6432       aopOp (result,ic,FALSE, FALSE);
6433       outBitC (result);
6434     }
6435   else
6436     {
6437       tlbl = newiTempLabel (NULL);
6438       toBoolean (left);
6439       emitcode ("jz", "!tlabel", tlbl->key + 100);
6440       toBoolean (right);
6441       emitcode ("", "!tlabeldef", tlbl->key + 100);
6442       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6443       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6444
6445       aopOp (result,ic,FALSE, FALSE);
6446       outBitAcc (result);
6447     }
6448     freeAsmop (result, NULL, ic, TRUE);
6449 }
6450
6451
6452 /*-----------------------------------------------------------------*/
6453 /* genOrOp - for || operation                                      */
6454 /*-----------------------------------------------------------------*/
6455 static void
6456 genOrOp (iCode * ic)
6457 {
6458   operand *left, *right, *result;
6459   symbol *tlbl;
6460
6461   D (emitcode (";", "genOrOp "););
6462
6463   /* note here that || operations that are in an
6464      if statement are taken away by backPatchLabels
6465      only those used in arthmetic operations remain */
6466   AOP_OP_2 (ic);
6467   AOP_SET_LOCALS (ic);
6468
6469   /* if both are bit variables */
6470   if (AOP_TYPE (left) == AOP_CRY &&
6471       AOP_TYPE (right) == AOP_CRY)
6472     {
6473       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6474       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6475       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6476       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6477
6478       aopOp (result,ic,FALSE, FALSE);
6479
6480       outBitC (result);
6481     }
6482   else
6483     {
6484       tlbl = newiTempLabel (NULL);
6485       toBoolean (left);
6486       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6487       toBoolean (right);
6488       emitcode ("", "!tlabeldef", tlbl->key + 100);
6489       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6490       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6491
6492       aopOp (result,ic,FALSE, FALSE);
6493
6494       outBitAcc (result);
6495     }
6496
6497   freeAsmop (result, NULL, ic, TRUE);
6498 }
6499
6500 /*-----------------------------------------------------------------*/
6501 /* isLiteralBit - test if lit == 2^n                               */
6502 /*-----------------------------------------------------------------*/
6503 static int
6504 isLiteralBit (unsigned long lit)
6505 {
6506   unsigned long pw[32] =
6507   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6508    0x100L, 0x200L, 0x400L, 0x800L,
6509    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6510    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6511    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6512    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6513    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6514   int idx;
6515
6516   for (idx = 0; idx < 32; idx++)
6517     if (lit == pw[idx])
6518       return idx + 1;
6519   return 0;
6520 }
6521
6522 /*-----------------------------------------------------------------*/
6523 /* continueIfTrue -                                                */
6524 /*-----------------------------------------------------------------*/
6525 static void
6526 continueIfTrue (iCode * ic)
6527 {
6528   if (IC_TRUE (ic))
6529     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6530   ic->generated = 1;
6531 }
6532
6533 /*-----------------------------------------------------------------*/
6534 /* jmpIfTrue -                                                     */
6535 /*-----------------------------------------------------------------*/
6536 static void
6537 jumpIfTrue (iCode * ic)
6538 {
6539   if (!IC_TRUE (ic))
6540     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6541   ic->generated = 1;
6542 }
6543
6544 /*-----------------------------------------------------------------*/
6545 /* jmpTrueOrFalse -                                                */
6546 /*-----------------------------------------------------------------*/
6547 static void
6548 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
6549 {
6550   // ugly but optimized by peephole
6551   if (IC_TRUE (ic))
6552     {
6553       symbol *nlbl = newiTempLabel (NULL);
6554       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
6555       emitcode ("", "!tlabeldef", tlbl->key + 100);
6556       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6557       emitcode ("", "!tlabeldef", nlbl->key + 100);
6558     }
6559   else
6560     {
6561       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6562       emitcode ("", "!tlabeldef", tlbl->key + 100);
6563     }
6564   ic->generated = 1;
6565 }
6566
6567 // Generate code to perform a bit-wise logic operation
6568 // on two operands in far space (assumed to already have been
6569 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
6570 // in far space. This requires pushing the result on the stack
6571 // then popping it into the result.
6572 static void
6573 genFarFarLogicOp(iCode *ic, char *logicOp)
6574 {
6575       int size, resultSize, compSize;
6576       int offset = 0;
6577
6578       TR_AP("#5");
6579       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
6580       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
6581                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
6582
6583       _startLazyDPSEvaluation();
6584       for (size = compSize; (size--); offset++)
6585       {
6586           MOVA (aopGet (AOP (IC_LEFT(ic)), offset, FALSE, FALSE, NULL));
6587           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
6588           MOVA (aopGet (AOP (IC_RIGHT(ic)), offset, FALSE, FALSE, NULL));
6589
6590           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
6591           emitcode ("push", "acc");
6592       }
6593       _endLazyDPSEvaluation();
6594
6595       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6596       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6597       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
6598
6599       resultSize = AOP_SIZE(IC_RESULT(ic));
6600
6601       ADJUST_PUSHED_RESULT(compSize, resultSize);
6602
6603       _startLazyDPSEvaluation();
6604       while (compSize--)
6605       {
6606           emitcode ("pop", "acc");
6607           aopPut (AOP (IC_RESULT (ic)), "a", compSize);
6608       }
6609       _endLazyDPSEvaluation();
6610       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
6611 }
6612
6613
6614 /*-----------------------------------------------------------------*/
6615 /* genAnd  - code for and                                          */
6616 /*-----------------------------------------------------------------*/
6617 static void
6618 genAnd (iCode * ic, iCode * ifx)
6619 {
6620   operand *left, *right, *result;
6621   int size, offset = 0;
6622   unsigned long lit = 0L;
6623   int bytelit;
6624   char buff[10];
6625   bool pushResult;
6626
6627   D (emitcode (";", "genAnd "););
6628
6629   AOP_OP_3_NOFATAL (ic, pushResult);
6630   AOP_SET_LOCALS (ic);
6631
6632   if (pushResult)
6633   {
6634       genFarFarLogicOp(ic, "anl");
6635       return;
6636   }
6637
6638 #ifdef DEBUG_TYPE
6639   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6640             AOP_TYPE (result),
6641             AOP_TYPE (left), AOP_TYPE (right));
6642   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6643             AOP_SIZE (result),
6644             AOP_SIZE (left), AOP_SIZE (right));
6645 #endif
6646
6647   /* if left is a literal & right is not then exchange them */
6648   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
6649 #ifdef LOGIC_OPS_BROKEN
6650     ||  AOP_NEEDSACC (left)
6651 #endif
6652     )
6653     {
6654       operand *tmp = right;
6655       right = left;
6656       left = tmp;
6657     }
6658
6659   /* if result = right then exchange left and right */
6660   if (sameRegs (AOP (result), AOP (right)))
6661     {
6662       operand *tmp = right;
6663       right = left;
6664       left = tmp;
6665     }
6666
6667   /* if right is bit then exchange them */
6668   if (AOP_TYPE (right) == AOP_CRY &&
6669       AOP_TYPE (left) != AOP_CRY)
6670     {
6671       operand *tmp = right;
6672       right = left;
6673       left = tmp;
6674     }
6675   if (AOP_TYPE (right) == AOP_LIT)
6676     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6677
6678   size = AOP_SIZE (result);
6679
6680   // if(bit & yy)
6681   // result = bit & yy;
6682   if (AOP_TYPE (left) == AOP_CRY)
6683     {
6684       // c = bit & literal;
6685       if (AOP_TYPE (right) == AOP_LIT)
6686         {
6687           if (lit & 1)
6688             {
6689               if (size && sameRegs (AOP (result), AOP (left)))
6690                 // no change
6691                 goto release;
6692               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6693             }
6694           else
6695             {
6696               // bit(result) = 0;
6697               if (size && (AOP_TYPE (result) == AOP_CRY))
6698                 {
6699                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6700                   goto release;
6701                 }
6702               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6703                 {
6704                   jumpIfTrue (ifx);
6705                   goto release;
6706                 }
6707               emitcode ("clr", "c");
6708             }
6709         }
6710       else
6711         {
6712           if (AOP_TYPE (right) == AOP_CRY)
6713             {
6714               // c = bit & bit;
6715               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6716               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6717             }
6718           else
6719             {
6720               // c = bit & val;
6721               MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
6722               // c = lsb
6723               emitcode ("rrc", "a");
6724               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6725             }
6726         }
6727       // bit = c
6728       // val = c
6729       if (size)
6730         outBitC (result);
6731       // if(bit & ...)
6732       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6733         genIfxJump (ifx, "c");
6734       goto release;
6735     }
6736
6737   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6738   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6739   if ((AOP_TYPE (right) == AOP_LIT) &&
6740       (AOP_TYPE (result) == AOP_CRY) &&
6741       (AOP_TYPE (left) != AOP_CRY))
6742     {
6743       int posbit = isLiteralBit (lit);
6744       /* left &  2^n */
6745       if (posbit)
6746         {
6747           posbit--;
6748           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE, NULL));
6749           // bit = left & 2^n
6750           if (size)
6751             emitcode ("mov", "c,acc.%d", posbit & 0x07);
6752           // if(left &  2^n)
6753           else
6754             {
6755               if (ifx)
6756                 {
6757                   SNPRINTF (buff, sizeof(buff),
6758                             "acc.%d", posbit & 0x07);
6759                   genIfxJump (ifx, buff);
6760                 }
6761               else
6762                   {
6763                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6764                   }
6765               goto release;
6766             }
6767         }
6768       else
6769         {
6770           symbol *tlbl = newiTempLabel (NULL);
6771           int sizel = AOP_SIZE (left);
6772           if (size)
6773             emitcode ("setb", "c");
6774           while (sizel--)
6775             {
6776               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6777                 {
6778                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6779                   // byte ==  2^n ?
6780                   if ((posbit = isLiteralBit (bytelit)) != 0)
6781                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
6782                   else
6783                     {
6784                       if (bytelit != 0x0FFL)
6785                         emitcode ("anl", "a,%s",
6786                           aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG));
6787                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6788                     }
6789                 }
6790               offset++;
6791             }
6792           // bit = left & literal
6793           if (size)
6794             {
6795               emitcode ("clr", "c");
6796               emitcode ("", "!tlabeldef", tlbl->key + 100);
6797             }
6798           // if(left & literal)
6799           else
6800             {
6801               if (ifx)
6802                 jmpTrueOrFalse (ifx, tlbl);
6803               else
6804                 emitcode ("", "!tlabeldef", tlbl->key + 100);
6805               goto release;
6806             }
6807         }
6808       outBitC (result);
6809       goto release;
6810     }
6811
6812   /* if left is same as result */
6813   if (sameRegs (AOP (result), AOP (left)))
6814     {
6815       for (; size--; offset++)
6816         {
6817           if (AOP_TYPE (right) == AOP_LIT)
6818             {
6819               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6820               if (bytelit == 0x0FF)
6821                 {
6822                   /* dummy read of volatile operand */
6823                   if (isOperandVolatile (left, FALSE))
6824                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6825                   else
6826                     continue;
6827                 }
6828               else if (bytelit == 0)
6829                 {
6830                   aopPut (AOP (result), zero, offset);
6831                 }
6832               else if (IS_AOP_PREG (result))
6833                 {
6834                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6835                   emitcode ("anl", "a,%s",
6836                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6837                   aopPut (AOP (result), "a", offset);
6838                 }
6839               else
6840                 emitcode ("anl", "%s,%s",
6841                           aopGet (AOP (left), offset, FALSE, TRUE, NULL),
6842                           aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6843             }
6844           else
6845             {
6846               if (AOP_TYPE (left) == AOP_ACC)
6847                 emitcode ("anl", "a,%s",
6848                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6849               else
6850                 {
6851                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6852                   if (IS_AOP_PREG (result))
6853                     {
6854                       emitcode ("anl", "a,%s",
6855                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6856                       aopPut (AOP (result), "a", offset);
6857                     }
6858                   else
6859                     emitcode ("anl", "%s,a",
6860                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6861                 }
6862             }
6863         }
6864     }
6865   else
6866     {
6867       // left & result in different registers
6868       if (AOP_TYPE (result) == AOP_CRY)
6869         {
6870           // result = bit
6871           // if(size), result in bit
6872           // if(!size && ifx), conditional oper: if(left & right)
6873           symbol *tlbl = newiTempLabel (NULL);
6874           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6875           if (size)
6876             emitcode ("setb", "c");
6877           while (sizer--)
6878             {
6879               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6880                 emitcode ("anl", "a,%s",
6881                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6882               } else {
6883                 if (AOP_TYPE(left)==AOP_ACC) {
6884                   emitcode("mov", "b,a");
6885                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6886                   emitcode("anl", "a,b");
6887                 }else {
6888                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6889                   emitcode ("anl", "a,%s",
6890                             aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
6891                 }
6892               }
6893               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6894               offset++;
6895             }
6896           if (size)
6897             {
6898               CLRC;
6899               emitcode ("", "!tlabeldef", tlbl->key + 100);
6900               outBitC (result);
6901             }
6902           else if (ifx)
6903             jmpTrueOrFalse (ifx, tlbl);
6904           else
6905             emitcode ("", "!tlabeldef", tlbl->key + 100);
6906         }
6907       else
6908         {
6909           for (; (size--); offset++)
6910             {
6911               // normal case
6912               // result = left & right
6913               if (AOP_TYPE (right) == AOP_LIT)
6914                 {
6915                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6916                   if (bytelit == 0x0FF)
6917                     {
6918                       aopPut (AOP (result),
6919                               aopGet (AOP (left), offset, FALSE, FALSE, NULL),
6920                               offset);
6921                       continue;
6922                     }
6923                   else if (bytelit == 0)
6924                     {
6925                       /* dummy read of volatile operand */
6926                       if (isOperandVolatile (left, FALSE))
6927                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6928                       aopPut (AOP (result), zero, offset);
6929                       continue;
6930                     }
6931                   D (emitcode (";", "better literal AND."););
6932                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6933                   emitcode ("anl", "a, %s", aopGet (AOP (right), offset,
6934                                                     FALSE, FALSE, DP2_RESULT_REG));
6935
6936                 }
6937               else
6938                 {
6939                   // faster than result <- left, anl result,right
6940                   // and better if result is SFR
6941                   if (AOP_TYPE (left) == AOP_ACC)
6942                     {
6943                       emitcode ("anl", "a,%s",
6944                                 aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6945                     }
6946                   else
6947                     {
6948                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
6949                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
6950                       {
6951                           emitcode("mov", "b,a");
6952                           rOp = "b";
6953                       }
6954
6955                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6956                       emitcode ("anl", "a,%s", rOp);
6957                     }
6958                 }
6959               aopPut (AOP (result), "a", offset);
6960             }
6961         }
6962     }
6963
6964 release:
6965   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6966   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6967   freeAsmop (result, NULL, ic, TRUE);
6968 }
6969
6970
6971 /*-----------------------------------------------------------------*/
6972 /* genOr  - code for or                                            */
6973 /*-----------------------------------------------------------------*/
6974 static void
6975 genOr (iCode * ic, iCode * ifx)
6976 {
6977   operand *left, *right, *result;
6978   int size, offset = 0;
6979   unsigned long lit = 0L;
6980   int bytelit = 0;
6981   bool     pushResult;
6982
6983   D (emitcode (";", "genOr "););
6984
6985   AOP_OP_3_NOFATAL (ic, pushResult);
6986   AOP_SET_LOCALS (ic);
6987
6988   if (pushResult)
6989   {
6990       genFarFarLogicOp(ic, "orl");
6991       return;
6992   }
6993
6994
6995 #ifdef DEBUG_TYPE
6996   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6997             AOP_TYPE (result),
6998             AOP_TYPE (left), AOP_TYPE (right));
6999   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7000             AOP_SIZE (result),
7001             AOP_SIZE (left), AOP_SIZE (right));
7002 #endif
7003
7004   /* if left is a literal & right is not then exchange them */
7005   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7006 #ifdef LOGIC_OPS_BROKEN
7007    || AOP_NEEDSACC (left) // I think this is a net loss now.
7008 #endif
7009       )
7010     {
7011       operand *tmp = right;
7012       right = left;
7013       left = tmp;
7014     }
7015
7016   /* if result = right then exchange them */
7017   if (sameRegs (AOP (result), AOP (right)))
7018     {
7019       operand *tmp = right;
7020       right = left;
7021       left = tmp;
7022     }
7023
7024   /* if right is bit then exchange them */
7025   if (AOP_TYPE (right) == AOP_CRY &&
7026       AOP_TYPE (left) != AOP_CRY)
7027     {
7028       operand *tmp = right;
7029       right = left;
7030       left = tmp;
7031     }
7032   if (AOP_TYPE (right) == AOP_LIT)
7033     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7034
7035   size = AOP_SIZE (result);
7036
7037   // if(bit | yy)
7038   // xx = bit | yy;
7039   if (AOP_TYPE (left) == AOP_CRY)
7040     {
7041       if (AOP_TYPE (right) == AOP_LIT)
7042         {
7043           // c = bit & literal;
7044           if (lit)
7045             {
7046               // lit != 0 => result = 1
7047               if (AOP_TYPE (result) == AOP_CRY)
7048                 {
7049                   if (size)
7050                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7051                   else if (ifx)
7052                     continueIfTrue (ifx);
7053                   goto release;
7054                 }
7055               emitcode ("setb", "c");
7056             }
7057           else
7058             {
7059               // lit == 0 => result = left
7060               if (size && sameRegs (AOP (result), AOP (left)))
7061                 goto release;
7062               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7063             }
7064         }
7065       else
7066         {
7067           if (AOP_TYPE (right) == AOP_CRY)
7068             {
7069               // c = bit | bit;
7070               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7071               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7072             }
7073           else
7074             {
7075               // c = bit | val;
7076               symbol *tlbl = newiTempLabel (NULL);
7077               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7078                 emitcode ("setb", "c");
7079               emitcode ("jb", "%s,!tlabel",
7080                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7081               toBoolean (right);
7082               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7083               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7084                 {
7085                   jmpTrueOrFalse (ifx, tlbl);
7086                   goto release;
7087                 }
7088               else
7089                 {
7090                   CLRC;
7091                   emitcode ("", "!tlabeldef", tlbl->key + 100);
7092                 }
7093             }
7094         }
7095       // bit = c
7096       // val = c
7097       if (size)
7098         outBitC (result);
7099       // if(bit | ...)
7100       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7101            genIfxJump (ifx, "c");
7102       goto release;
7103     }
7104
7105   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7106   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7107   if ((AOP_TYPE (right) == AOP_LIT) &&
7108       (AOP_TYPE (result) == AOP_CRY) &&
7109       (AOP_TYPE (left) != AOP_CRY))
7110     {
7111       if (lit)
7112         {
7113           // result = 1
7114           if (size)
7115             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7116           else
7117             continueIfTrue (ifx);
7118           goto release;
7119         }
7120       else
7121         {
7122           // lit = 0, result = boolean(left)
7123           if (size)
7124             emitcode ("setb", "c");
7125           toBoolean (right);
7126           if (size)
7127             {
7128               symbol *tlbl = newiTempLabel (NULL);
7129               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7130               CLRC;
7131               emitcode ("", "!tlabeldef", tlbl->key + 100);
7132             }
7133           else
7134             {
7135               genIfxJump (ifx, "a");
7136               goto release;
7137             }
7138         }
7139       outBitC (result);
7140       goto release;
7141     }
7142
7143   /* if left is same as result */
7144   if (sameRegs (AOP (result), AOP (left)))
7145     {
7146       for (; size--; offset++)
7147         {
7148           if (AOP_TYPE (right) == AOP_LIT)
7149             {
7150               bytelit = (int)((lit >> (offset * 8)) & 0x0FFL);
7151               if (bytelit == 0x00L)
7152                 {
7153                   /* dummy read of volatile operand */
7154                   if (isOperandVolatile (left, FALSE))
7155                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7156                   else
7157                     continue;
7158                 }
7159               else if (bytelit == 0x0FF)
7160                 {
7161                   aopPut (AOP (result), "#0xFF", offset);
7162                 }
7163               else if (IS_AOP_PREG (left))
7164                 {
7165                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7166                   emitcode ("orl", "a,%s",
7167                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7168                   aopPut (AOP (result), "a", offset);
7169                 }
7170               else
7171                 {
7172                   emitcode ("orl", "%s,%s",
7173                             aopGet (AOP (left), offset, FALSE, TRUE, NULL),
7174                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7175                 }
7176             }
7177           else
7178             {
7179               if (AOP_TYPE (left) == AOP_ACC)
7180                 {
7181                   emitcode ("orl", "a,%s",
7182                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7183                 }
7184               else
7185                 {
7186                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7187                   if (IS_AOP_PREG (left))
7188                     {
7189                       emitcode ("orl", "a,%s",
7190                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7191                       aopPut (AOP (result), "a", offset);
7192                     }
7193                   else
7194                     {
7195                       emitcode ("orl", "%s,a",
7196                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7197                     }
7198                 }
7199             }
7200         }
7201     }
7202   else
7203     {
7204       // left & result in different registers
7205       if (AOP_TYPE (result) == AOP_CRY)
7206         {
7207           // result = bit
7208           // if(size), result in bit
7209           // if(!size && ifx), conditional oper: if(left | right)
7210           symbol *tlbl = newiTempLabel (NULL);
7211           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7212           if (size)
7213             emitcode ("setb", "c");
7214           while (sizer--)
7215             {
7216               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7217                 emitcode ("orl", "a,%s",
7218                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7219               } else {
7220                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7221                 emitcode ("orl", "a,%s",
7222                           aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
7223               }
7224               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7225               offset++;
7226             }
7227           if (size)
7228             {
7229               CLRC;
7230               emitcode ("", "!tlabeldef", tlbl->key + 100);
7231               outBitC (result);
7232             }
7233           else if (ifx)
7234             jmpTrueOrFalse (ifx, tlbl);
7235           else
7236             emitcode ("", "!tlabeldef", tlbl->key + 100);
7237         }
7238       else
7239         {
7240             _startLazyDPSEvaluation();
7241           for (; (size--); offset++)
7242             {
7243               // normal case
7244               // result = left & right
7245               if (AOP_TYPE (right) == AOP_LIT)
7246                 {
7247                   bytelit = (int)((lit >> (offset * 8)) & 0x0FFL);
7248                   if (bytelit == 0x00L)
7249                     {
7250                       aopPut (AOP (result),
7251                               aopGet (AOP (left), offset, FALSE, FALSE, NULL),
7252                               offset);
7253                       continue;
7254                     }
7255                   else if (bytelit == 0x0FF)
7256                     {
7257                       /* dummy read of volatile operand */
7258                       if (isOperandVolatile (left, FALSE))
7259                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7260                       aopPut (AOP (result), "#0xFF", offset);
7261                       continue;
7262                     }
7263                   D (emitcode (";", "better literal OR."););
7264                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7265                   emitcode ("orl", "a, %s",
7266                             aopGet (AOP (right), offset,
7267                                     FALSE, FALSE, DP2_RESULT_REG));
7268
7269                 }
7270               else
7271                 {
7272                   // faster than result <- left, anl result,right
7273                   // and better if result is SFR
7274                   if (AOP_TYPE (left) == AOP_ACC)
7275                     {
7276                       emitcode ("orl", "a,%s",
7277                                 aopGet (AOP (right), offset,
7278                                         FALSE, FALSE, DP2_RESULT_REG));
7279                     }
7280                   else
7281                     {
7282                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7283
7284                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7285                       {
7286                           emitcode("mov", "b,a");
7287                           rOp = "b";
7288                       }
7289
7290                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7291                       emitcode ("orl", "a,%s", rOp);
7292                     }
7293                 }
7294               aopPut (AOP (result), "a", offset);
7295             }
7296             _endLazyDPSEvaluation();
7297         }
7298     }
7299
7300 release:
7301   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7302   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7303   freeAsmop (result, NULL, ic, TRUE);
7304 }
7305
7306 /*-----------------------------------------------------------------*/
7307 /* genXor - code for xclusive or                                   */
7308 /*-----------------------------------------------------------------*/
7309 static void
7310 genXor (iCode * ic, iCode * ifx)
7311 {
7312   operand *left, *right, *result;
7313   int size, offset = 0;
7314   unsigned long lit = 0L;
7315   int bytelit = 0;
7316   bool pushResult;
7317
7318   D (emitcode (";", "genXor "););
7319
7320   AOP_OP_3_NOFATAL (ic, pushResult);
7321   AOP_SET_LOCALS (ic);
7322
7323   if (pushResult)
7324   {
7325       genFarFarLogicOp(ic, "xrl");
7326       return;
7327   }
7328
7329 #ifdef DEBUG_TYPE
7330   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7331             AOP_TYPE (result),
7332             AOP_TYPE (left), AOP_TYPE (right));
7333   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7334             AOP_SIZE (result),
7335             AOP_SIZE (left), AOP_SIZE (right));
7336 #endif
7337
7338   /* if left is a literal & right is not ||
7339      if left needs acc & right does not */
7340   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7341 #ifdef LOGIC_OPS_BROKEN
7342       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7343 #endif
7344      )
7345     {
7346       operand *tmp = right;
7347       right = left;
7348       left = tmp;
7349     }
7350
7351   /* if result = right then exchange them */
7352   if (sameRegs (AOP (result), AOP (right)))
7353     {
7354       operand *tmp = right;
7355       right = left;
7356       left = tmp;
7357     }
7358
7359   /* if right is bit then exchange them */
7360   if (AOP_TYPE (right) == AOP_CRY &&
7361       AOP_TYPE (left) != AOP_CRY)
7362     {
7363       operand *tmp = right;
7364       right = left;
7365       left = tmp;
7366     }
7367   if (AOP_TYPE (right) == AOP_LIT)
7368     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7369
7370   size = AOP_SIZE (result);
7371
7372   // if(bit ^ yy)
7373   // xx = bit ^ yy;
7374   if (AOP_TYPE (left) == AOP_CRY)
7375     {
7376       if (AOP_TYPE (right) == AOP_LIT)
7377         {
7378           // c = bit & literal;
7379           if (lit >> 1)
7380             {
7381               // lit>>1  != 0 => result = 1
7382               if (AOP_TYPE (result) == AOP_CRY)
7383                 {
7384                   if (size)
7385                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7386                   else if (ifx)
7387                     continueIfTrue (ifx);
7388                   goto release;
7389                 }
7390               emitcode ("setb", "c");
7391             }
7392           else
7393             {
7394               // lit == (0 or 1)
7395               if (lit == 0)
7396                 {
7397                   // lit == 0, result = left
7398                   if (size && sameRegs (AOP (result), AOP (left)))
7399                     goto release;
7400                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7401                 }
7402               else
7403                 {
7404                   // lit == 1, result = not(left)
7405                   if (size && sameRegs (AOP (result), AOP (left)))
7406                     {
7407                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7408                       goto release;
7409                     }
7410                   else
7411                     {
7412                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7413                       emitcode ("cpl", "c");
7414                     }
7415                 }
7416             }
7417
7418         }
7419       else
7420         {
7421           // right != literal
7422           symbol *tlbl = newiTempLabel (NULL);
7423           if (AOP_TYPE (right) == AOP_CRY)
7424             {
7425               // c = bit ^ bit;
7426               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7427             }
7428           else
7429             {
7430               int sizer = AOP_SIZE (right);
7431               // c = bit ^ val
7432               // if val>>1 != 0, result = 1
7433               emitcode ("setb", "c");
7434               while (sizer)
7435                 {
7436                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE, NULL));
7437                   if (sizer == 1)
7438                     // test the msb of the lsb
7439                     emitcode ("anl", "a,#!constbyte",0xfe);
7440                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
7441                   sizer--;
7442                 }
7443               // val = (0,1)
7444               emitcode ("rrc", "a");
7445             }
7446           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7447           emitcode ("cpl", "c");
7448           emitcode ("", "!tlabeldef", (tlbl->key + 100));
7449         }
7450       // bit = c
7451       // val = c
7452       if (size)
7453         outBitC (result);
7454       // if(bit | ...)
7455       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7456         genIfxJump (ifx, "c");
7457       goto release;
7458     }
7459
7460   /* if left is same as result */
7461   if (sameRegs (AOP (result), AOP (left)))
7462     {
7463       for (; size--; offset++)
7464         {
7465           if (AOP_TYPE (right) == AOP_LIT)
7466             {
7467               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7468               if (bytelit == 0x00L)
7469                 {
7470                   /* dummy read of volatile operand */
7471                   if (isOperandVolatile (left, FALSE))
7472                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7473                   else
7474                     continue;
7475                 }
7476               else if (IS_AOP_PREG (left))
7477                 {
7478                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7479                   emitcode ("xrl", "a,%s",
7480                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7481                   aopPut (AOP (result), "a", offset);
7482                 }
7483               else
7484                 {
7485                   emitcode ("xrl", "%s,%s",
7486                             aopGet (AOP (left), offset, FALSE, TRUE, NULL),
7487                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7488                 }
7489             }
7490           else
7491             {
7492               if (AOP_TYPE (left) == AOP_ACC)
7493                 emitcode ("xrl", "a,%s",
7494                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7495               else
7496                 {
7497                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7498                   if (IS_AOP_PREG (left))
7499                     {
7500                       emitcode ("xrl", "a,%s",
7501                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7502                       aopPut (AOP (result), "a", offset);
7503                     }
7504                   else
7505                     emitcode ("xrl", "%s,a",
7506                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7507                 }
7508             }
7509         }
7510     }
7511   else
7512     {
7513       // left & result in different registers
7514       if (AOP_TYPE (result) == AOP_CRY)
7515         {
7516           // result = bit
7517           // if(size), result in bit
7518           // if(!size && ifx), conditional oper: if(left ^ right)
7519           symbol *tlbl = newiTempLabel (NULL);
7520           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7521
7522           if (size)
7523             emitcode ("setb", "c");
7524           while (sizer--)
7525             {
7526               if ((AOP_TYPE (right) == AOP_LIT) &&
7527                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7528                 {
7529                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7530                 }
7531               else
7532                 {
7533                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7534                     emitcode ("xrl", "a,%s",
7535                               aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7536                   } else {
7537                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7538                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7539                       {
7540                           emitcode("mov", "b,a");
7541                           rOp = "b";
7542                       }
7543
7544                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7545                       emitcode ("xrl", "a,%s", rOp);
7546                   }
7547                 }
7548               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7549               offset++;
7550             }
7551           if (size)
7552             {
7553               CLRC;
7554               emitcode ("", "!tlabeldef", tlbl->key + 100);
7555               outBitC (result);
7556             }
7557           else if (ifx)
7558             jmpTrueOrFalse (ifx, tlbl);
7559         }
7560       else
7561         {
7562         for (; (size--); offset++)
7563           {
7564             // normal case
7565             // result = left & right
7566             if (AOP_TYPE (right) == AOP_LIT)
7567               {
7568                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
7569                   {
7570                     aopPut (AOP (result),
7571                             aopGet (AOP (left), offset, FALSE, FALSE, NULL),
7572                             offset);
7573                     continue;
7574                   }
7575                 D (emitcode (";", "better literal XOR."););
7576                 MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7577                 emitcode ("xrl", "a, %s",
7578                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7579               }
7580             else
7581               {
7582                 // faster than result <- left, anl result,right
7583                 // and better if result is SFR
7584                 if (AOP_TYPE (left) == AOP_ACC)
7585                   {
7586                     emitcode ("xrl", "a,%s",
7587                               aopGet (AOP (right), offset,
7588                                       FALSE, FALSE, DP2_RESULT_REG));
7589                   }
7590                 else
7591                   {
7592                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7593                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7594                       {
7595                           emitcode("mov", "b,a");
7596                           rOp = "b";
7597                       }
7598
7599                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7600                       emitcode ("xrl", "a,%s", rOp);
7601                   }
7602               }
7603             aopPut (AOP (result), "a", offset);
7604           }
7605         }
7606
7607     }
7608
7609 release:
7610   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7611   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7612   freeAsmop (result, NULL, ic, TRUE);
7613 }
7614
7615 /*-----------------------------------------------------------------*/
7616 /* genInline - write the inline code out                           */
7617 /*-----------------------------------------------------------------*/
7618 static void
7619 genInline (iCode * ic)
7620 {
7621   char *buffer, *bp, *bp1;
7622
7623   D (emitcode (";", "genInline "); );
7624
7625   _G.inLine += (!options.asmpeep);
7626
7627   buffer = Safe_strdup(IC_INLINE(ic));
7628   bp = buffer;
7629   bp1 = buffer;
7630
7631   /* emit each line as a code */
7632   while (*bp)
7633     {
7634       if (*bp == '\n')
7635         {
7636           *bp++ = '\0';
7637           emitcode (bp1, "");
7638           bp1 = bp;
7639         }
7640       else
7641         {
7642           if (*bp == ':')
7643             {
7644               bp++;
7645               *bp = '\0';
7646               bp++;
7647               emitcode (bp1, "");
7648               bp1 = bp;
7649             }
7650           else
7651             bp++;
7652         }
7653     }
7654   if (bp1 != bp)
7655     emitcode (bp1, "");
7656   /*     emitcode("",buffer); */
7657   _G.inLine -= (!options.asmpeep);
7658 }
7659
7660 /*-----------------------------------------------------------------*/
7661 /* genRRC - rotate right with carry                                */
7662 /*-----------------------------------------------------------------*/
7663 static void
7664 genRRC (iCode * ic)
7665 {
7666   operand *left, *result;
7667   int     size, offset;
7668
7669   D (emitcode (";", "genRRC "););
7670
7671   /* rotate right with carry */
7672   left = IC_LEFT (ic);
7673   result = IC_RESULT (ic);
7674   aopOp (left, ic, FALSE, FALSE);
7675   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7676
7677   /* move it to the result */
7678   size = AOP_SIZE (result);
7679   offset = size - 1;
7680   CLRC;
7681
7682   _startLazyDPSEvaluation ();
7683   while (size--)
7684     {
7685       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7686       emitcode ("rrc", "a");
7687       if (AOP_SIZE (result) > 1)
7688         aopPut (AOP (result), "a", offset--);
7689     }
7690   _endLazyDPSEvaluation ();
7691
7692   /* now we need to put the carry into the
7693      highest order byte of the result */
7694   if (AOP_SIZE (result) > 1)
7695     {
7696       MOVA (aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE, NULL));
7697     }
7698   emitcode ("mov", "acc.7,c");
7699   aopPut (AOP (result), "a", AOP_SIZE (result) - 1);
7700   freeAsmop (left, NULL, ic, TRUE);
7701   freeAsmop (result, NULL, ic, TRUE);
7702 }
7703
7704 /*-----------------------------------------------------------------*/
7705 /* genRLC - generate code for rotate left with carry               */
7706 /*-----------------------------------------------------------------*/
7707 static void
7708 genRLC (iCode * ic)
7709 {
7710   operand *left, *result;
7711   int size, offset;
7712   char *l;
7713
7714   D (emitcode (";", "genRLC "););
7715
7716   /* rotate right with carry */
7717   left = IC_LEFT (ic);
7718   result = IC_RESULT (ic);
7719   aopOp (left, ic, FALSE, FALSE);
7720   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7721
7722   /* move it to the result */
7723   size = AOP_SIZE (result);
7724   offset = 0;
7725   if (size--)
7726     {
7727       l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7728       MOVA (l);
7729       emitcode ("add", "a,acc");
7730       if (AOP_SIZE (result) > 1)
7731         {
7732           aopPut (AOP (result), "a", offset++);
7733         }
7734
7735       _startLazyDPSEvaluation ();
7736       while (size--)
7737         {
7738           l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7739           MOVA (l);
7740           emitcode ("rlc", "a");
7741           if (AOP_SIZE (result) > 1)
7742             aopPut (AOP (result), "a", offset++);
7743         }
7744       _endLazyDPSEvaluation ();
7745     }
7746   /* now we need to put the carry into the
7747      highest order byte of the result */
7748   if (AOP_SIZE (result) > 1)
7749     {
7750       l = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
7751       MOVA (l);
7752     }
7753   emitcode ("mov", "acc.0,c");
7754   aopPut (AOP (result), "a", 0);
7755   freeAsmop (left, NULL, ic, TRUE);
7756   freeAsmop (result, NULL, ic, TRUE);
7757 }
7758
7759 /*-----------------------------------------------------------------*/
7760 /* genGetHbit - generates code get highest order bit               */
7761 /*-----------------------------------------------------------------*/
7762 static void
7763 genGetHbit (iCode * ic)
7764 {
7765   operand *left, *result;
7766   left = IC_LEFT (ic);
7767   result = IC_RESULT (ic);
7768   aopOp (left, ic, FALSE, FALSE);
7769   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7770
7771   D (emitcode (";", "genGetHbit "););
7772
7773   /* get the highest order byte into a */
7774   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
7775   if (AOP_TYPE (result) == AOP_CRY)
7776     {
7777       emitcode ("rlc", "a");
7778       outBitC (result);
7779     }
7780   else
7781     {
7782       emitcode ("rl", "a");
7783       emitcode ("anl", "a,#1");
7784       outAcc (result);
7785     }
7786
7787
7788   freeAsmop (left, NULL, ic, TRUE);
7789   freeAsmop (result, NULL, ic, TRUE);
7790 }
7791
7792 /*-----------------------------------------------------------------*/
7793 /* genSwap - generates code to swap nibbles or bytes               */
7794 /*-----------------------------------------------------------------*/
7795 static void
7796 genSwap (iCode * ic)
7797 {
7798   operand *left, *result;
7799
7800   D(emitcode (";     genSwap",""));
7801
7802   left = IC_LEFT (ic);
7803   result = IC_RESULT (ic);
7804   aopOp (left, ic, FALSE, FALSE);
7805   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7806
7807   _startLazyDPSEvaluation ();
7808   switch (AOP_SIZE (left))
7809     {
7810     case 1: /* swap nibbles in byte */
7811       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7812       emitcode ("swap", "a");
7813       aopPut (AOP (result), "a", 0);
7814       break;
7815     case 2: /* swap bytes in word */
7816       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7817         {
7818           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7819           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7820           aopPut (AOP (result), "a", 1);
7821         }
7822       else if (operandsEqu (left, result))
7823         {
7824           char * reg = "a";
7825           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7826           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
7827             {
7828               emitcode ("mov", "b,a");
7829               reg = "b";
7830               _G.bInUse=1;
7831             }
7832           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7833           aopPut (AOP (result), reg, 1);
7834           _G.bInUse=0;
7835         }
7836       else
7837         {
7838           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7839           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE, NULL), 1);
7840         }
7841       break;
7842     default:
7843       wassertl(FALSE, "unsupported SWAP operand size");
7844     }
7845   _endLazyDPSEvaluation ();
7846
7847   freeAsmop (left, NULL, ic, TRUE);
7848   freeAsmop (result, NULL, ic, TRUE);
7849 }
7850
7851 /*-----------------------------------------------------------------*/
7852 /* AccRol - rotate left accumulator by known count                 */
7853 /*-----------------------------------------------------------------*/
7854 static void
7855 AccRol (int shCount)
7856 {
7857   shCount &= 0x0007;            // shCount : 0..7
7858
7859   switch (shCount)
7860     {
7861     case 0:
7862       break;
7863     case 1:
7864       emitcode ("rl", "a");
7865       break;
7866     case 2:
7867       emitcode ("rl", "a");
7868       emitcode ("rl", "a");
7869       break;
7870     case 3:
7871       emitcode ("swap", "a");
7872       emitcode ("rr", "a");
7873       break;
7874     case 4:
7875       emitcode ("swap", "a");
7876       break;
7877     case 5:
7878       emitcode ("swap", "a");
7879       emitcode ("rl", "a");
7880       break;
7881     case 6:
7882       emitcode ("rr", "a");
7883       emitcode ("rr", "a");
7884       break;
7885     case 7:
7886       emitcode ("rr", "a");
7887       break;
7888     }
7889 }
7890
7891 /*-----------------------------------------------------------------*/
7892 /* AccLsh - left shift accumulator by known count                  */
7893 /*-----------------------------------------------------------------*/
7894 static void
7895 AccLsh (int shCount)
7896 {
7897   if (shCount != 0)
7898     {
7899       if (shCount == 1)
7900         emitcode ("add", "a,acc");
7901       else if (shCount == 2)
7902         {
7903           emitcode ("add", "a,acc");
7904           emitcode ("add", "a,acc");
7905         }
7906       else
7907         {
7908           /* rotate left accumulator */
7909           AccRol (shCount);
7910           /* and kill the lower order bits */
7911           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
7912         }
7913     }
7914 }
7915
7916 /*-----------------------------------------------------------------*/
7917 /* AccRsh - right shift accumulator by known count                 */
7918 /*-----------------------------------------------------------------*/
7919 static void
7920 AccRsh (int shCount)
7921 {
7922   if (shCount != 0)
7923     {
7924       if (shCount == 1)
7925         {
7926           CLRC;
7927           emitcode ("rrc", "a");
7928         }
7929       else
7930         {
7931           /* rotate right accumulator */
7932           AccRol (8 - shCount);
7933           /* and kill the higher order bits */
7934           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7935         }
7936     }
7937 }
7938
7939 #ifdef BETTER_LITERAL_SHIFT
7940 /*-----------------------------------------------------------------*/
7941 /* AccSRsh - signed right shift accumulator by known count                 */
7942 /*-----------------------------------------------------------------*/
7943 static void
7944 AccSRsh (int shCount)
7945 {
7946   symbol *tlbl;
7947   if (shCount != 0)
7948     {
7949       if (shCount == 1)
7950         {
7951           emitcode ("mov", "c,acc.7");
7952           emitcode ("rrc", "a");
7953         }
7954       else if (shCount == 2)
7955         {
7956           emitcode ("mov", "c,acc.7");
7957           emitcode ("rrc", "a");
7958           emitcode ("mov", "c,acc.7");
7959           emitcode ("rrc", "a");
7960         }
7961       else
7962         {
7963           tlbl = newiTempLabel (NULL);
7964           /* rotate right accumulator */
7965           AccRol (8 - shCount);
7966           /* and kill the higher order bits */
7967           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7968           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7969           emitcode ("orl", "a,#!constbyte",
7970                     (unsigned char) ~SRMask[shCount]);
7971           emitcode ("", "!tlabeldef", tlbl->key + 100);
7972         }
7973     }
7974 }
7975 #endif
7976
7977 #ifdef BETTER_LITERAL_SHIFT
7978 /*-----------------------------------------------------------------*/
7979 /* shiftR1Left2Result - shift right one byte from left to result   */
7980 /*-----------------------------------------------------------------*/
7981 static void
7982 shiftR1Left2Result (operand * left, int offl,
7983                     operand * result, int offr,
7984                     int shCount, int sign)
7985 {
7986   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7987   /* shift right accumulator */
7988   if (sign)
7989     AccSRsh (shCount);
7990   else
7991     AccRsh (shCount);
7992   aopPut (AOP (result), "a", offr);
7993 }
7994 #endif
7995
7996 #ifdef BETTER_LITERAL_SHIFT
7997 /*-----------------------------------------------------------------*/
7998 /* shiftL1Left2Result - shift left one byte from left to result    */
7999 /*-----------------------------------------------------------------*/
8000 static void
8001 shiftL1Left2Result (operand * left, int offl,
8002                     operand * result, int offr, int shCount)
8003 {
8004   MOVA(aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8005   /* shift left accumulator */
8006   AccLsh (shCount);
8007   aopPut (AOP (result), "a", offr);
8008 }
8009 #endif
8010
8011 #ifdef BETTER_LITERAL_SHIFT
8012 /*-----------------------------------------------------------------*/
8013 /* movLeft2Result - move byte from left to result                  */
8014 /*-----------------------------------------------------------------*/
8015 static void
8016 movLeft2Result (operand * left, int offl,
8017                 operand * result, int offr, int sign)
8018 {
8019   char *l;
8020   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8021   {
8022       l = aopGet (AOP (left), offl, FALSE, FALSE, NULL);
8023
8024       if (*l == '@' && (IS_AOP_PREG (result)))
8025       {
8026           emitcode ("mov", "a,%s", l);
8027           aopPut (AOP (result), "a", offr);
8028       }
8029       else
8030       {
8031           if (!sign)
8032           {
8033             aopPut (AOP (result), l, offr);
8034           }
8035           else
8036             {
8037               /* MSB sign in acc.7 ! */
8038               if (getDataSize (left) == offl + 1)
8039                 {
8040                   emitcode ("mov", "a,%s", l);
8041                   aopPut (AOP (result), "a", offr);
8042                 }
8043             }
8044       }
8045   }
8046 }
8047 #endif
8048
8049 #ifdef BETTER_LITERAL_SHIFT
8050 /*-----------------------------------------------------------------*/
8051 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8052 /*-----------------------------------------------------------------*/
8053 static void
8054 AccAXRrl1 (char *x)
8055 {
8056   emitcode ("rrc", "a");
8057   emitcode ("xch", "a,%s", x);
8058   emitcode ("rrc", "a");
8059   emitcode ("xch", "a,%s", x);
8060 }
8061 #endif
8062
8063 #ifdef BETTER_LITERAL_SHIFT
8064 //REMOVE ME!!!
8065 /*-----------------------------------------------------------------*/
8066 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8067 /*-----------------------------------------------------------------*/
8068 static void
8069 AccAXLrl1 (char *x)
8070 {
8071   emitcode ("xch", "a,%s", x);
8072   emitcode ("rlc", "a");
8073   emitcode ("xch", "a,%s", x);
8074   emitcode ("rlc", "a");
8075 }
8076 #endif
8077
8078 #ifdef BETTER_LITERAL_SHIFT
8079 /*-----------------------------------------------------------------*/
8080 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8081 /*-----------------------------------------------------------------*/
8082 static void
8083 AccAXLsh1 (char *x)
8084 {
8085   emitcode ("xch", "a,%s", x);
8086   emitcode ("add", "a,acc");
8087   emitcode ("xch", "a,%s", x);
8088   emitcode ("rlc", "a");
8089 }
8090 #endif
8091
8092 #ifdef BETTER_LITERAL_SHIFT
8093 /*-----------------------------------------------------------------*/
8094 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8095 /*-----------------------------------------------------------------*/
8096 static void
8097 AccAXLsh (char *x, int shCount)
8098 {
8099   switch (shCount)
8100     {
8101     case 0:
8102       break;
8103     case 1:
8104       AccAXLsh1 (x);
8105       break;
8106     case 2:
8107       AccAXLsh1 (x);
8108       AccAXLsh1 (x);
8109       break;
8110     case 3:
8111     case 4:
8112     case 5:                     // AAAAABBB:CCCCCDDD
8113
8114       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8115
8116       emitcode ("anl", "a,#!constbyte",
8117                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8118
8119       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8120
8121       AccRol (shCount);         // DDDCCCCC:BBB00000
8122
8123       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8124
8125       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8126
8127       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8128
8129       emitcode ("anl", "a,#!constbyte",
8130                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8131
8132       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8133
8134       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8135
8136       break;
8137     case 6:                     // AAAAAABB:CCCCCCDD
8138       emitcode ("anl", "a,#!constbyte",
8139                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8140       emitcode ("mov", "c,acc.0");      // c = B
8141       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8142 #if 0
8143       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8144       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8145 #else
8146       emitcode("rrc","a");
8147       emitcode("xch","a,%s", x);
8148       emitcode("rrc","a");
8149       emitcode("mov","c,acc.0"); //<< get correct bit
8150       emitcode("xch","a,%s", x);
8151
8152       emitcode("rrc","a");
8153       emitcode("xch","a,%s", x);
8154       emitcode("rrc","a");
8155       emitcode("xch","a,%s", x);
8156 #endif
8157       break;
8158     case 7:                     // a:x <<= 7
8159
8160       emitcode ("anl", "a,#!constbyte",
8161                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8162
8163       emitcode ("mov", "c,acc.0");      // c = B
8164
8165       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8166
8167       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8168
8169       break;
8170     default:
8171       break;
8172     }
8173 }
8174 #endif
8175
8176 #ifdef BETTER_LITERAL_SHIFT
8177 //REMOVE ME!!!
8178 /*-----------------------------------------------------------------*/
8179 /* AccAXRsh - right shift a:x known count (0..7)                   */
8180 /*-----------------------------------------------------------------*/
8181 static void
8182 AccAXRsh (char *x, int shCount)
8183 {
8184   switch (shCount)
8185     {
8186     case 0:
8187       break;
8188     case 1:
8189       CLRC;
8190       AccAXRrl1 (x);            // 0->a:x
8191
8192       break;
8193     case 2:
8194       CLRC;
8195       AccAXRrl1 (x);            // 0->a:x
8196
8197       CLRC;
8198       AccAXRrl1 (x);            // 0->a:x
8199
8200       break;
8201     case 3:
8202     case 4:
8203     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8204
8205       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8206
8207       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8208
8209       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8210
8211       emitcode ("anl", "a,#!constbyte",
8212                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8213
8214       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8215
8216       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8217
8218       emitcode ("anl", "a,#!constbyte",
8219                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8220
8221       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8222
8223       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8224
8225       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8226
8227       break;
8228     case 6:                     // AABBBBBB:CCDDDDDD
8229
8230       emitcode ("mov", "c,acc.7");
8231       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8232
8233       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8234
8235       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8236
8237       emitcode ("anl", "a,#!constbyte",
8238                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8239
8240       break;
8241     case 7:                     // ABBBBBBB:CDDDDDDD
8242
8243       emitcode ("mov", "c,acc.7");      // c = A
8244
8245       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8246
8247       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8248
8249       emitcode ("anl", "a,#!constbyte",
8250                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8251
8252       break;
8253     default:
8254       break;
8255     }
8256 }
8257 #endif
8258
8259 #ifdef BETTER_LITERAL_SHIFT
8260 /*-----------------------------------------------------------------*/
8261 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8262 /*-----------------------------------------------------------------*/
8263 static void
8264 AccAXRshS (char *x, int shCount)
8265 {
8266   symbol *tlbl;
8267   switch (shCount)
8268     {
8269     case 0:
8270       break;
8271     case 1:
8272       emitcode ("mov", "c,acc.7");
8273       AccAXRrl1 (x);            // s->a:x
8274
8275       break;
8276     case 2:
8277       emitcode ("mov", "c,acc.7");
8278       AccAXRrl1 (x);            // s->a:x
8279
8280       emitcode ("mov", "c,acc.7");
8281       AccAXRrl1 (x);            // s->a:x
8282
8283       break;
8284     case 3:
8285     case 4:
8286     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8287
8288       tlbl = newiTempLabel (NULL);
8289       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8290
8291       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8292
8293       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8294
8295       emitcode ("anl", "a,#!constbyte",
8296                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8297
8298       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8299
8300       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8301
8302       emitcode ("anl", "a,#!constbyte",
8303                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8304
8305       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8306
8307       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8308
8309       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8310
8311       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8312       emitcode ("orl", "a,#!constbyte",
8313                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8314
8315       emitcode ("", "!tlabeldef", tlbl->key + 100);
8316       break;                    // SSSSAAAA:BBBCCCCC
8317
8318     case 6:                     // AABBBBBB:CCDDDDDD
8319
8320       tlbl = newiTempLabel (NULL);
8321       emitcode ("mov", "c,acc.7");
8322       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8323
8324       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8325
8326       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8327
8328       emitcode ("anl", "a,#!constbyte",
8329                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8330
8331       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8332       emitcode ("orl", "a,#!constbyte",
8333                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8334
8335       emitcode ("", "!tlabeldef", tlbl->key + 100);
8336       break;
8337     case 7:                     // ABBBBBBB:CDDDDDDD
8338
8339       tlbl = newiTempLabel (NULL);
8340       emitcode ("mov", "c,acc.7");      // c = A
8341
8342       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8343
8344       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8345
8346       emitcode ("anl", "a,#!constbyte",
8347                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8348
8349       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8350       emitcode ("orl", "a,#!constbyte",
8351                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8352
8353       emitcode ("", "!tlabeldef", tlbl->key + 100);
8354       break;
8355     default:
8356       break;
8357     }
8358 }
8359 #endif
8360
8361 #ifdef BETTER_LITERAL_SHIFT
8362 static void
8363 _loadLeftIntoAx(char    **lsb,
8364                 operand *left,
8365                 operand *result,
8366                 int     offl,
8367                 int     offr)
8368 {
8369   // Get the initial value from left into a pair of registers.
8370   // MSB must be in A, LSB can be any register.
8371   //
8372   // If the result is held in registers, it is an optimization
8373   // if the LSB can be held in the register which will hold the,
8374   // result LSB since this saves us from having to copy it into
8375   // the result following AccAXLsh.
8376   //
8377   // If the result is addressed indirectly, this is not a gain.
8378   if (AOP_NEEDSACC(result))
8379   {
8380        char *leftByte;
8381
8382        _startLazyDPSEvaluation();
8383       if (AOP_TYPE(left) == AOP_DPTR2)
8384        {
8385            // Get MSB in A.
8386            MOVA(aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL));
8387            // get LSB in DP2_RESULT_REG.
8388            leftByte = aopGet(AOP(left), offl, FALSE, FALSE, DP2_RESULT_REG);
8389            assert(!strcmp(leftByte, DP2_RESULT_REG));
8390        }
8391        else
8392        {
8393            // get LSB into DP2_RESULT_REG
8394            leftByte = aopGet (AOP(left), offl, FALSE, FALSE, NULL);
8395            if (strcmp(leftByte, DP2_RESULT_REG))
8396            {
8397                TR_AP("#7");
8398                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8399            }
8400            // And MSB in A.
8401            leftByte = aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL);
8402            assert(strcmp(leftByte, DP2_RESULT_REG));
8403            MOVA(leftByte);
8404        }
8405        _endLazyDPSEvaluation();
8406        *lsb = DP2_RESULT_REG;
8407   }
8408   else
8409   {
8410       if (sameRegs (AOP (result), AOP (left)) &&
8411         ((offl + MSB16) == offr))
8412       {
8413           /* don't crash result[offr] */
8414           MOVA(aopGet(AOP(left), offl, FALSE, FALSE, NULL));
8415           emitcode ("xch", "a,%s",
8416                     aopGet(AOP(left), offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8417       }
8418       else
8419       {
8420           movLeft2Result (left, offl, result, offr, 0);
8421           MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, NULL));
8422       }
8423       *lsb = aopGet(AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG);
8424       assert(strcmp(*lsb,"a"));
8425   }
8426 }
8427
8428 static void
8429 _storeAxResults(char    *lsb,
8430                 operand *result,
8431                 int     offr)
8432 {
8433   _startLazyDPSEvaluation();
8434   if (AOP_NEEDSACC(result))
8435   {
8436       /* We have to explicitly update the result LSB.
8437        */
8438       emitcode("xch","a,%s", lsb);
8439       aopPut(AOP(result), "a", offr);
8440       emitcode("mov","a,%s", lsb);
8441   }
8442   if (getDataSize (result) > 1)
8443   {
8444       aopPut (AOP (result), "a", offr + MSB16);
8445   }
8446   _endLazyDPSEvaluation();
8447 }
8448
8449 /*-----------------------------------------------------------------*/
8450 /* shiftL2Left2Result - shift left two bytes from left to result   */
8451 /*-----------------------------------------------------------------*/
8452 static void
8453 shiftL2Left2Result (operand * left, int offl,
8454                     operand * result, int offr, int shCount)
8455 {
8456   char *lsb;
8457
8458   _loadLeftIntoAx(&lsb, left, result, offl, offr);
8459
8460   AccAXLsh (lsb, shCount);
8461
8462   _storeAxResults(lsb, result, offr);
8463 }
8464 #endif
8465
8466 #ifdef BETTER_LITERAL_SHIFT
8467 /*-----------------------------------------------------------------*/
8468 /* shiftR2Left2Result - shift right two bytes from left to result  */
8469 /*-----------------------------------------------------------------*/
8470 static void
8471 shiftR2Left2Result (operand * left, int offl,
8472                     operand * result, int offr,
8473                     int shCount, int sign)
8474 {
8475   char *lsb;
8476
8477   _loadLeftIntoAx(&lsb, left, result, offl, offr);
8478
8479   /* a:x >> shCount (x = lsb(result)) */
8480   if (sign)
8481   {
8482      AccAXRshS(lsb, shCount);
8483   }
8484   else
8485   {
8486     AccAXRsh(lsb, shCount);
8487   }
8488
8489   _storeAxResults(lsb, result, offr);
8490 }
8491 #endif
8492
8493 /*-----------------------------------------------------------------*/
8494 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8495 /*-----------------------------------------------------------------*/
8496 static void
8497 shiftLLeftOrResult (operand * left, int offl,
8498                     operand * result, int offr, int shCount)
8499 {
8500   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8501   /* shift left accumulator */
8502   AccLsh (shCount);
8503   /* or with result */
8504   emitcode ("orl", "a,%s",
8505             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
8506   /* back to result */
8507   aopPut (AOP (result), "a", offr);
8508 }
8509
8510 #if 0
8511 //REMOVE ME!!!
8512 /*-----------------------------------------------------------------*/
8513 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8514 /*-----------------------------------------------------------------*/
8515 static void
8516 shiftRLeftOrResult (operand * left, int offl,
8517                     operand * result, int offr, int shCount)
8518 {
8519   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8520   /* shift right accumulator */
8521   AccRsh (shCount);
8522   /* or with result */
8523   emitcode ("orl", "a,%s",
8524             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
8525   /* back to result */
8526   aopPut (AOP (result), "a", offr);
8527 }
8528 #endif
8529
8530 #ifdef BETTER_LITERAL_SHIFT
8531 /*-----------------------------------------------------------------*/
8532 /* genlshOne - left shift a one byte quantity by known count       */
8533 /*-----------------------------------------------------------------*/
8534 static void
8535 genlshOne (operand * result, operand * left, int shCount)
8536 {
8537   D (emitcode (";", "genlshOne "););
8538   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8539 }
8540 #endif
8541
8542 #ifdef BETTER_LITERAL_SHIFT
8543 /*-----------------------------------------------------------------*/
8544 /* genlshTwo - left shift two bytes by known amount != 0           */
8545 /*-----------------------------------------------------------------*/
8546 static void
8547 genlshTwo (operand * result, operand * left, int shCount)
8548 {
8549   int size;
8550
8551   D (emitcode (";", "genlshTwo "););
8552
8553   size = getDataSize (result);
8554
8555   /* if shCount >= 8 */
8556   if (shCount >= 8)
8557   {
8558       shCount -= 8;
8559
8560       _startLazyDPSEvaluation();
8561
8562       if (size > 1)
8563         {
8564           if (shCount)
8565           {
8566             _endLazyDPSEvaluation();
8567             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8568             aopPut (AOP (result), zero, LSB);
8569           }
8570           else
8571           {
8572             movLeft2Result (left, LSB, result, MSB16, 0);
8573             aopPut (AOP (result), zero, LSB);
8574             _endLazyDPSEvaluation();
8575           }
8576         }
8577         else
8578         {
8579           aopPut (AOP (result), zero, LSB);
8580           _endLazyDPSEvaluation();
8581         }
8582   }
8583
8584   /*  1 <= shCount <= 7 */
8585   else
8586     {
8587       if (size == 1)
8588       {
8589         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8590       }
8591       else
8592       {
8593         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8594       }
8595     }
8596 }
8597 #endif
8598
8599 #if 0
8600 //REMOVE ME!!!
8601 /*-----------------------------------------------------------------*/
8602 /* shiftLLong - shift left one long from left to result            */
8603 /* offl = LSB or MSB16                                             */
8604 /*-----------------------------------------------------------------*/
8605 static void
8606 shiftLLong (operand * left, operand * result, int offr)
8607 {
8608   char *l;
8609   int size = AOP_SIZE (result);
8610
8611   if (size >= LSB + offr)
8612     {
8613       l = aopGet (AOP (left), LSB, FALSE, FALSE, NULL);
8614       MOVA (l);
8615       emitcode ("add", "a,acc");
8616       if (sameRegs (AOP (left), AOP (result)) &&
8617           size >= MSB16 + offr && offr != LSB)
8618         emitcode ("xch", "a,%s",
8619                   aopGet (AOP (left), LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
8620       else
8621         aopPut (AOP (result), "a", LSB + offr);
8622     }
8623
8624   if (size >= MSB16 + offr)
8625     {
8626       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8627         {
8628           MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, TRUE));
8629         }
8630       emitcode ("rlc", "a");
8631       if (sameRegs (AOP (left), AOP (result)) &&
8632           size >= MSB24 + offr && offr != LSB)
8633         emitcode ("xch", "a,%s",
8634                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
8635       else
8636         aopPut (AOP (result), "a", MSB16 + offr);
8637     }
8638
8639   if (size >= MSB24 + offr)
8640     {
8641       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8642         {
8643           MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
8644         }
8645       emitcode ("rlc", "a");
8646       if (sameRegs (AOP (left), AOP (result)) &&
8647           size >= MSB32 + offr && offr != LSB)
8648         emitcode ("xch", "a,%s",
8649                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
8650       else
8651         aopPut (AOP (result), "a", MSB24 + offr);
8652     }
8653
8654   if (size > MSB32 + offr)
8655     {
8656       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8657         {
8658           MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
8659         }
8660       emitcode ("rlc", "a");
8661       aopPut (AOP (result), "a", MSB32 + offr);
8662     }
8663   if (offr != LSB)
8664     aopPut (AOP (result), zero, LSB);
8665 }
8666 #endif
8667
8668 #if 0
8669 //REMOVE ME!!!
8670 /*-----------------------------------------------------------------*/
8671 /* genlshFour - shift four byte by a known amount != 0             */
8672 /*-----------------------------------------------------------------*/
8673 static void
8674 genlshFour (operand * result, operand * left, int shCount)
8675 {
8676   int size;
8677
8678   D (emitcode (";", "genlshFour ");
8679     );
8680
8681   size = AOP_SIZE (result);
8682
8683   /* if shifting more that 3 bytes */
8684   if (shCount >= 24)
8685     {
8686       shCount -= 24;
8687       if (shCount)
8688         /* lowest order of left goes to the highest
8689            order of the destination */
8690         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8691       else
8692         movLeft2Result (left, LSB, result, MSB32, 0);
8693       aopPut (AOP (result), zero, LSB);
8694       aopPut (AOP (result), zero, MSB16);
8695       aopPut (AOP (result), zero, MSB24);
8696       return;
8697     }
8698
8699   /* more than two bytes */
8700   else if (shCount >= 16)
8701     {
8702       /* lower order two bytes goes to higher order two bytes */
8703       shCount -= 16;
8704       /* if some more remaining */
8705       if (shCount)
8706         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8707       else
8708         {
8709           movLeft2Result (left, MSB16, result, MSB32, 0);
8710           movLeft2Result (left, LSB, result, MSB24, 0);
8711         }
8712       aopPut (AOP (result), zero, MSB16);
8713       aopPut (AOP (result), zero, LSB);
8714       return;
8715     }
8716
8717   /* if more than 1 byte */
8718   else if (shCount >= 8)
8719     {
8720       /* lower order three bytes goes to higher order  three bytes */
8721       shCount -= 8;
8722       if (size == 2)
8723         {
8724           if (shCount)
8725             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8726           else
8727             movLeft2Result (left, LSB, result, MSB16, 0);
8728         }
8729       else
8730         {                       /* size = 4 */
8731           if (shCount == 0)
8732             {
8733               movLeft2Result (left, MSB24, result, MSB32, 0);
8734               movLeft2Result (left, MSB16, result, MSB24, 0);
8735               movLeft2Result (left, LSB, result, MSB16, 0);
8736               aopPut (AOP (result), zero, LSB);
8737             }
8738           else if (shCount == 1)
8739             shiftLLong (left, result, MSB16);
8740           else
8741             {
8742               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8743               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8744               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8745               aopPut (AOP (result), zero, LSB);
8746             }
8747         }
8748     }
8749
8750   /* 1 <= shCount <= 7 */
8751   else if (shCount <= 2)
8752     {
8753       shiftLLong (left, result, LSB);
8754       if (shCount == 2)
8755         shiftLLong (result, result, LSB);
8756     }
8757   /* 3 <= shCount <= 7, optimize */
8758   else
8759     {
8760       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8761       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8762       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8763     }
8764 }
8765 #endif
8766
8767 #ifdef BETTER_LITERAL_SHIFT
8768 /*-----------------------------------------------------------------*/
8769 /* genLeftShiftLiteral - left shifting by known count              */
8770 /*-----------------------------------------------------------------*/
8771 static bool
8772 genLeftShiftLiteral (operand * left,
8773                      operand * right,
8774                      operand * result,
8775                      iCode * ic)
8776 {
8777   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8778   int size;
8779
8780   size = getSize (operandType (result));
8781
8782   D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
8783
8784   /* We only handle certain easy cases so far. */
8785   if ((shCount != 0)
8786    && (shCount < (size * 8))
8787    && (size != 1)
8788    && (size != 2))
8789   {
8790       D(emitcode (";", "genLeftShiftLiteral wimping out"););
8791       return FALSE;
8792   }
8793
8794   freeAsmop (right, NULL, ic, TRUE);
8795
8796   aopOp(left, ic, FALSE, FALSE);
8797   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
8798
8799 #if 0 // debug spew
8800   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
8801   {
8802         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
8803         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
8804         {
8805            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
8806         }
8807   }
8808   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
8809   {
8810         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
8811         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
8812         {
8813            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
8814         }
8815   }
8816 #endif
8817
8818 #if VIEW_SIZE
8819   emitcode ("; shift left ", "result %d, left %d", size,
8820             AOP_SIZE (left));
8821 #endif
8822
8823   /* I suppose that the left size >= result size */
8824   if (shCount == 0)
8825   {
8826         _startLazyDPSEvaluation();
8827         while (size--)
8828         {
8829           movLeft2Result (left, size, result, size, 0);
8830         }
8831         _endLazyDPSEvaluation();
8832   }
8833   else if (shCount >= (size * 8))
8834   {
8835     _startLazyDPSEvaluation();
8836     while (size--)
8837     {
8838       aopPut (AOP (result), zero, size);
8839     }
8840     _endLazyDPSEvaluation();
8841   }
8842   else
8843   {
8844       switch (size)
8845         {
8846         case 1:
8847           genlshOne (result, left, shCount);
8848           break;
8849
8850         case 2:
8851           genlshTwo (result, left, shCount);
8852           break;
8853 #if 0
8854         case 4:
8855           genlshFour (result, left, shCount);
8856           break;
8857 #endif
8858         default:
8859           fprintf(stderr, "*** ack! mystery literal shift!\n");
8860           break;
8861         }
8862     }
8863   freeAsmop (left, NULL, ic, TRUE);
8864   freeAsmop (result, NULL, ic, TRUE);
8865   return TRUE;
8866 }
8867 #endif
8868
8869 /*-----------------------------------------------------------------*/
8870 /* genLeftShift - generates code for left shifting                 */
8871 /*-----------------------------------------------------------------*/
8872 static void
8873 genLeftShift (iCode * ic)
8874 {
8875   operand *left, *right, *result;
8876   int size, offset;
8877   char *l;
8878   symbol *tlbl, *tlbl1;
8879
8880   D (emitcode (";", "genLeftShift "););
8881
8882   right = IC_RIGHT (ic);
8883   left = IC_LEFT (ic);
8884   result = IC_RESULT (ic);
8885
8886   aopOp (right, ic, FALSE, FALSE);
8887
8888
8889 #ifdef BETTER_LITERAL_SHIFT
8890   /* if the shift count is known then do it
8891      as efficiently as possible */
8892   if (AOP_TYPE (right) == AOP_LIT)
8893     {
8894       if (genLeftShiftLiteral (left, right, result, ic))
8895       {
8896         return;
8897       }
8898     }
8899 #endif
8900
8901   /* shift count is unknown then we have to form
8902      a loop get the loop count in B : Note: we take
8903      only the lower order byte since shifting
8904      more that 32 bits make no sense anyway, ( the
8905      largest size of an object can be only 32 bits ) */
8906
8907   if (AOP_TYPE (right) == AOP_LIT)
8908   {
8909       /* Really should be handled by genLeftShiftLiteral,
8910        * but since I'm too lazy to fix that today, at least we can make
8911        * some small improvement.
8912        */
8913        emitcode("mov", "b,#!constbyte",
8914                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
8915   }
8916   else
8917   {
8918       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
8919       emitcode ("inc", "b");
8920   }
8921   freeAsmop (right, NULL, ic, TRUE);
8922   aopOp (left, ic, FALSE, FALSE);
8923   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8924
8925   /* now move the left to the result if they are not the
8926      same */
8927   if (!sameRegs (AOP (left), AOP (result)) &&
8928       AOP_SIZE (result) > 1)
8929     {
8930
8931       size = AOP_SIZE (result);
8932       offset = 0;
8933       _startLazyDPSEvaluation ();
8934       while (size--)
8935         {
8936           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
8937           if (*l == '@' && (IS_AOP_PREG (result)))
8938             {
8939
8940               emitcode ("mov", "a,%s", l);
8941               aopPut (AOP (result), "a", offset);
8942             }
8943           else
8944             aopPut (AOP (result), l, offset);
8945           offset++;
8946         }
8947       _endLazyDPSEvaluation ();
8948     }
8949
8950   tlbl = newiTempLabel (NULL);
8951   size = AOP_SIZE (result);
8952   offset = 0;
8953   tlbl1 = newiTempLabel (NULL);
8954
8955   /* if it is only one byte then */
8956   if (size == 1)
8957     {
8958       symbol *tlbl1 = newiTempLabel (NULL);
8959
8960       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
8961       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8962       emitcode ("", "!tlabeldef", tlbl->key + 100);
8963       emitcode ("add", "a,acc");
8964       emitcode ("", "!tlabeldef", tlbl1->key + 100);
8965       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8966       aopPut (AOP (result), "a", 0);
8967       goto release;
8968     }
8969
8970   reAdjustPreg (AOP (result));
8971
8972   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8973   emitcode ("", "!tlabeldef", tlbl->key + 100);
8974   MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8975   emitcode ("add", "a,acc");
8976   aopPut (AOP (result), "a", offset++);
8977   _startLazyDPSEvaluation ();
8978   while (--size)
8979     {
8980       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8981       emitcode ("rlc", "a");
8982       aopPut (AOP (result), "a", offset++);
8983     }
8984   _endLazyDPSEvaluation ();
8985   reAdjustPreg (AOP (result));
8986
8987   emitcode ("", "!tlabeldef", tlbl1->key + 100);
8988   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8989 release:
8990   freeAsmop (left, NULL, ic, TRUE);
8991   freeAsmop (result, NULL, ic, TRUE);
8992 }
8993
8994 #ifdef BETTER_LITERAL_SHIFT
8995 /*-----------------------------------------------------------------*/
8996 /* genrshOne - right shift a one byte quantity by known count      */
8997 /*-----------------------------------------------------------------*/
8998 static void
8999 genrshOne (operand * result, operand * left,
9000            int shCount, int sign)
9001 {
9002   D (emitcode (";", "genrshOne"););
9003   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9004 }
9005 #endif
9006
9007 #ifdef BETTER_LITERAL_SHIFT
9008 /*-----------------------------------------------------------------*/
9009 /* genrshTwo - right shift two bytes by known amount != 0          */
9010 /*-----------------------------------------------------------------*/
9011 static void
9012 genrshTwo (operand * result, operand * left,
9013            int shCount, int sign)
9014 {
9015   D (emitcode (";", "genrshTwo"););
9016
9017   /* if shCount >= 8 */
9018   if (shCount >= 8)
9019     {
9020       shCount -= 8;
9021       _startLazyDPSEvaluation();
9022       if (shCount)
9023       {
9024         shiftR1Left2Result (left, MSB16, result, LSB,
9025                             shCount, sign);
9026       }
9027       else
9028       {
9029         movLeft2Result (left, MSB16, result, LSB, sign);
9030       }
9031       addSign (result, MSB16, sign);
9032       _endLazyDPSEvaluation();
9033     }
9034
9035   /*  1 <= shCount <= 7 */
9036   else
9037   {
9038     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9039   }
9040 }
9041 #endif
9042
9043 /*-----------------------------------------------------------------*/
9044 /* shiftRLong - shift right one long from left to result           */
9045 /* offl = LSB or MSB16                                             */
9046 /*-----------------------------------------------------------------*/
9047 static void
9048 shiftRLong (operand * left, int offl,
9049             operand * result, int sign)
9050 {
9051   int isSameRegs=sameRegs(AOP(left),AOP(result));
9052
9053   if (isSameRegs && offl>1) {
9054     // we are in big trouble, but this shouldn't happen
9055     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9056   }
9057
9058   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
9059
9060   if (offl==MSB16) {
9061     // shift is > 8
9062     if (sign) {
9063       emitcode ("rlc", "a");
9064       emitcode ("subb", "a,acc");
9065       emitcode ("xch", "a,%s",
9066                 aopGet(AOP(left), MSB32, FALSE, FALSE, DP2_RESULT_REG));
9067     } else {
9068       aopPut (AOP(result), zero, MSB32);
9069     }
9070   }
9071
9072   if (!sign) {
9073     emitcode ("clr", "c");
9074   } else {
9075     emitcode ("mov", "c,acc.7");
9076   }
9077
9078   emitcode ("rrc", "a");
9079
9080   if (isSameRegs && offl==MSB16) {
9081     emitcode ("xch",
9082               "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE, DP2_RESULT_REG));
9083   } else {
9084     aopPut (AOP (result), "a", MSB32);
9085     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
9086   }
9087
9088   emitcode ("rrc", "a");
9089   if (isSameRegs && offl==1) {
9090     emitcode ("xch", "a,%s",
9091               aopGet (AOP (left), MSB16, FALSE, FALSE, DP2_RESULT_REG));
9092   } else {
9093     aopPut (AOP (result), "a", MSB24);
9094     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, NULL));
9095   }
9096   emitcode ("rrc", "a");
9097   aopPut (AOP (result), "a", MSB16 - offl);
9098
9099   if (offl == LSB)
9100     {
9101       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE, NULL));
9102       emitcode ("rrc", "a");
9103       aopPut (AOP (result), "a", LSB);
9104     }
9105 }
9106
9107 /*-----------------------------------------------------------------*/
9108 /* genrshFour - shift four byte by a known amount != 0             */
9109 /*-----------------------------------------------------------------*/
9110 static void
9111 genrshFour (operand * result, operand * left,
9112             int shCount, int sign)
9113 {
9114   D (emitcode (";", "genrshFour"););
9115
9116   /* if shifting more that 3 bytes */
9117   if (shCount >= 24)
9118     {
9119       shCount -= 24;
9120       _startLazyDPSEvaluation();
9121       if (shCount)
9122         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9123       else
9124         movLeft2Result (left, MSB32, result, LSB, sign);
9125       addSign (result, MSB16, sign);
9126       _endLazyDPSEvaluation();
9127     }
9128   else if (shCount >= 16)
9129     {
9130       shCount -= 16;
9131       _startLazyDPSEvaluation();
9132       if (shCount)
9133         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9134       else
9135         {
9136           movLeft2Result (left, MSB24, result, LSB, 0);
9137           movLeft2Result (left, MSB32, result, MSB16, sign);
9138         }
9139       addSign (result, MSB24, sign);
9140       _endLazyDPSEvaluation();
9141     }
9142   else if (shCount >= 8)
9143     {
9144       shCount -= 8;
9145       _startLazyDPSEvaluation();
9146       if (shCount == 1)
9147         {
9148             shiftRLong (left, MSB16, result, sign);
9149         }
9150       else if (shCount == 0)
9151         {
9152           movLeft2Result (left, MSB16, result, LSB, 0);
9153           movLeft2Result (left, MSB24, result, MSB16, 0);
9154           movLeft2Result (left, MSB32, result, MSB24, sign);
9155           addSign (result, MSB32, sign);
9156         }
9157       else
9158         {
9159           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9160           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9161           /* the last shift is signed */
9162           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9163           addSign (result, MSB32, sign);
9164         }
9165         _endLazyDPSEvaluation();
9166     }
9167   else
9168     {
9169         /* 1 <= shCount <= 7 */
9170       if (shCount <= 2)
9171         {
9172           shiftRLong (left, LSB, result, sign);
9173           if (shCount == 2)
9174             shiftRLong (result, LSB, result, sign);
9175         }
9176       else
9177         {
9178           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9179           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9180           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9181         }
9182     }
9183 }
9184
9185 #ifdef BETTER_LITERAL_SHIFT
9186 /*-----------------------------------------------------------------*/
9187 /* genRightShiftLiteral - right shifting by known count            */
9188 /*-----------------------------------------------------------------*/
9189 static bool
9190 genRightShiftLiteral (operand * left,
9191                       operand * right,
9192                       operand * result,
9193                       iCode * ic,
9194                       int sign)
9195 {
9196   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9197   int size;
9198
9199   size = getSize (operandType (result));
9200
9201   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9202
9203   /* We only handle certain easy cases so far. */
9204   if ((shCount != 0)
9205    && (shCount < (size * 8))
9206    && (size != 1)
9207    && (size != 2)
9208    && (size != 4))
9209   {
9210       D(emitcode (";", "genRightShiftLiteral wimping out"););
9211       return FALSE;
9212   }
9213
9214   freeAsmop (right, NULL, ic, TRUE);
9215
9216   aopOp (left, ic, FALSE, FALSE);
9217   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9218
9219 #if VIEW_SIZE
9220   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9221             AOP_SIZE (left));
9222 #endif
9223
9224   /* test the LEFT size !!! */
9225
9226   /* I suppose that the left size >= result size */
9227   if (shCount == 0)
9228   {
9229       size = getDataSize (result);
9230       _startLazyDPSEvaluation();
9231       while (size--)
9232       {
9233         movLeft2Result (left, size, result, size, 0);
9234       }
9235       _endLazyDPSEvaluation();
9236   }
9237   else if (shCount >= (size * 8))
9238     {
9239       if (sign)
9240       {
9241         /* get sign in acc.7 */
9242         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE, NULL));
9243       }
9244       addSign (result, LSB, sign);
9245     }
9246   else
9247     {
9248       switch (size)
9249         {
9250         case 1:
9251           genrshOne (result, left, shCount, sign);
9252           break;
9253
9254         case 2:
9255           genrshTwo (result, left, shCount, sign);
9256           break;
9257 #if 1
9258         case 4:
9259           genrshFour (result, left, shCount, sign);
9260           break;
9261 #endif
9262         default:
9263           break;
9264         }
9265     }
9266   freeAsmop (left, NULL, ic, TRUE);
9267   freeAsmop (result, NULL, ic, TRUE);
9268
9269   return TRUE;
9270 }
9271 #endif
9272
9273 /*-----------------------------------------------------------------*/
9274 /* genSignedRightShift - right shift of signed number              */
9275 /*-----------------------------------------------------------------*/
9276 static void
9277 genSignedRightShift (iCode * ic)
9278 {
9279   operand *right, *left, *result;
9280   int size, offset;
9281   char *l;
9282   symbol *tlbl, *tlbl1;
9283
9284   D (emitcode (";", "genSignedRightShift "););
9285
9286   /* we do it the hard way put the shift count in b
9287      and loop thru preserving the sign */
9288
9289   right = IC_RIGHT (ic);
9290   left = IC_LEFT (ic);
9291   result = IC_RESULT (ic);
9292
9293   aopOp (right, ic, FALSE, FALSE);
9294
9295 #ifdef BETTER_LITERAL_SHIFT
9296   if (AOP_TYPE (right) == AOP_LIT)
9297     {
9298       if (genRightShiftLiteral (left, right, result, ic, 1))
9299       {
9300         return;
9301       }
9302     }
9303 #endif
9304   /* shift count is unknown then we have to form
9305      a loop get the loop count in B : Note: we take
9306      only the lower order byte since shifting
9307      more that 32 bits make no sense anyway, ( the
9308      largest size of an object can be only 32 bits ) */
9309
9310   if (AOP_TYPE (right) == AOP_LIT)
9311   {
9312       /* Really should be handled by genRightShiftLiteral,
9313        * but since I'm too lazy to fix that today, at least we can make
9314        * some small improvement.
9315        */
9316        emitcode("mov", "b,#!constbyte",
9317                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9318   }
9319   else
9320   {
9321         MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
9322         emitcode ("inc", "b");
9323   }
9324   freeAsmop (right, NULL, ic, TRUE);
9325   aopOp (left, ic, FALSE, FALSE);
9326   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9327
9328   /* now move the left to the result if they are not the
9329      same */
9330   if (!sameRegs (AOP (left), AOP (result)) &&
9331       AOP_SIZE (result) > 1)
9332     {
9333
9334       size = AOP_SIZE (result);
9335       offset = 0;
9336       _startLazyDPSEvaluation ();
9337       while (size--)
9338         {
9339           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
9340           if (*l == '@' && IS_AOP_PREG (result))
9341             {
9342
9343               emitcode ("mov", "a,%s", l);
9344               aopPut (AOP (result), "a", offset);
9345             }
9346           else
9347             aopPut (AOP (result), l, offset);
9348           offset++;
9349         }
9350       _endLazyDPSEvaluation ();
9351     }
9352
9353   /* mov the highest order bit to OVR */
9354   tlbl = newiTempLabel (NULL);
9355   tlbl1 = newiTempLabel (NULL);
9356
9357   size = AOP_SIZE (result);
9358   offset = size - 1;
9359   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
9360   emitcode ("rlc", "a");
9361   emitcode ("mov", "ov,c");
9362   /* if it is only one byte then */
9363   if (size == 1)
9364     {
9365       MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9366       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9367       emitcode ("", "!tlabeldef", tlbl->key + 100);
9368       emitcode ("mov", "c,ov");
9369       emitcode ("rrc", "a");
9370       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9371       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9372       aopPut (AOP (result), "a", 0);
9373       goto release;
9374     }
9375
9376   reAdjustPreg (AOP (result));
9377   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9378   emitcode ("", "!tlabeldef", tlbl->key + 100);
9379   emitcode ("mov", "c,ov");
9380   _startLazyDPSEvaluation ();
9381   while (size--)
9382     {
9383       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
9384       emitcode ("rrc", "a");
9385       aopPut (AOP (result), "a", offset--);
9386     }
9387   _endLazyDPSEvaluation ();
9388   reAdjustPreg (AOP (result));
9389   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9390   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9391
9392 release:
9393   freeAsmop (left, NULL, ic, TRUE);
9394   freeAsmop (result, NULL, ic, TRUE);
9395 }
9396
9397 /*-----------------------------------------------------------------*/
9398 /* genRightShift - generate code for right shifting                */
9399 /*-----------------------------------------------------------------*/
9400 static void
9401 genRightShift (iCode * ic)
9402 {
9403   operand *right, *left, *result;
9404   sym_link *letype;
9405   int size, offset;
9406   char *l;
9407   symbol *tlbl, *tlbl1;
9408
9409   D (emitcode (";", "genRightShift "););
9410
9411   /* if signed then we do it the hard way preserve the
9412      sign bit moving it inwards */
9413   letype = getSpec (operandType (IC_LEFT (ic)));
9414
9415   if (!SPEC_USIGN (letype))
9416     {
9417       genSignedRightShift (ic);
9418       return;
9419     }
9420
9421   /* signed & unsigned types are treated the same : i.e. the
9422      signed is NOT propagated inwards : quoting from the
9423      ANSI - standard : "for E1 >> E2, is equivalent to division
9424      by 2**E2 if unsigned or if it has a non-negative value,
9425      otherwise the result is implementation defined ", MY definition
9426      is that the sign does not get propagated */
9427
9428   right = IC_RIGHT (ic);
9429   left = IC_LEFT (ic);
9430   result = IC_RESULT (ic);
9431
9432   aopOp (right, ic, FALSE, FALSE);
9433
9434 #ifdef BETTER_LITERAL_SHIFT
9435   /* if the shift count is known then do it
9436      as efficiently as possible */
9437   if (AOP_TYPE (right) == AOP_LIT)
9438     {
9439       if (genRightShiftLiteral (left, right, result, ic, 0))
9440       {
9441         return;
9442       }
9443     }
9444 #endif
9445
9446   /* shift count is unknown then we have to form
9447      a loop get the loop count in B : Note: we take
9448      only the lower order byte since shifting
9449      more that 32 bits make no sense anyway, ( the
9450      largest size of an object can be only 32 bits ) */
9451
9452   if (AOP_TYPE (right) == AOP_LIT)
9453   {
9454       /* Really should be handled by genRightShiftLiteral,
9455        * but since I'm too lazy to fix that today, at least we can make
9456        * some small improvement.
9457        */
9458        emitcode("mov", "b,#!constbyte",
9459                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9460   }
9461   else
9462   {
9463       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
9464       emitcode ("inc", "b");
9465   }
9466   freeAsmop (right, NULL, ic, TRUE);
9467   aopOp (left, ic, FALSE, FALSE);
9468   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9469
9470   /* now move the left to the result if they are not the
9471      same */
9472   if (!sameRegs (AOP (left), AOP (result)) &&
9473       AOP_SIZE (result) > 1)
9474     {
9475
9476       size = AOP_SIZE (result);
9477       offset = 0;
9478       _startLazyDPSEvaluation ();
9479       while (size--)
9480         {
9481           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
9482           if (*l == '@' && IS_AOP_PREG (result))
9483             {
9484
9485               emitcode ("mov", "a,%s", l);
9486               aopPut (AOP (result), "a", offset);
9487             }
9488           else
9489             aopPut (AOP (result), l, offset);
9490           offset++;
9491         }
9492       _endLazyDPSEvaluation ();
9493     }
9494
9495   tlbl = newiTempLabel (NULL);
9496   tlbl1 = newiTempLabel (NULL);
9497   size = AOP_SIZE (result);
9498   offset = size - 1;
9499
9500   /* if it is only one byte then */
9501   if (size == 1)
9502     {
9503       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9504       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9505       emitcode ("", "!tlabeldef", tlbl->key + 100);
9506       CLRC;
9507       emitcode ("rrc", "a");
9508       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9509       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9510       aopPut (AOP (result), "a", 0);
9511       goto release;
9512     }
9513
9514   reAdjustPreg (AOP (result));
9515   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9516   emitcode ("", "!tlabeldef", tlbl->key + 100);
9517   CLRC;
9518   _startLazyDPSEvaluation ();
9519   while (size--)
9520     {
9521       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
9522       emitcode ("rrc", "a");
9523       aopPut (AOP (result), "a", offset--);
9524     }
9525   _endLazyDPSEvaluation ();
9526   reAdjustPreg (AOP (result));
9527
9528   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9529   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9530
9531 release:
9532   freeAsmop (left, NULL, ic, TRUE);
9533   freeAsmop (result, NULL, ic, TRUE);
9534 }
9535
9536
9537 /*-----------------------------------------------------------------*/
9538 /* emitPtrByteGet - emits code to get a byte into A through a      */
9539 /*                  pointer register (R0, R1, or DPTR). The        */
9540 /*                  original value of A can be preserved in B.     */
9541 /*-----------------------------------------------------------------*/
9542 static void
9543 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9544 {
9545   switch (p_type)
9546     {
9547     case IPOINTER:
9548     case POINTER:
9549       if (preserveAinB)
9550         emitcode ("mov", "b,a");
9551       emitcode ("mov", "a,@%s", rname);
9552       break;
9553
9554     case PPOINTER:
9555       if (preserveAinB)
9556         emitcode ("mov", "b,a");
9557       emitcode ("movx", "a,@%s", rname);
9558       break;
9559
9560     case FPOINTER:
9561       if (preserveAinB)
9562         emitcode ("mov", "b,a");
9563       emitcode ("movx", "a,@dptr");
9564       break;
9565
9566     case CPOINTER:
9567       if (preserveAinB)
9568         emitcode ("mov", "b,a");
9569       emitcode ("clr", "a");
9570       emitcode ("movc", "a,@a+dptr");
9571       break;
9572
9573     case GPOINTER:
9574       if (preserveAinB)
9575         {
9576           emitcode ("push", "b");
9577           emitcode ("push", "acc");
9578         }
9579       emitcode ("lcall", "__gptrget");
9580       if (preserveAinB)
9581         emitcode ("pop", "b");
9582       break;
9583     }
9584 }
9585
9586 /*-----------------------------------------------------------------*/
9587 /* emitPtrByteSet - emits code to set a byte from src through a    */
9588 /*                  pointer register (R0, R1, or DPTR).            */
9589 /*-----------------------------------------------------------------*/
9590 static void
9591 emitPtrByteSet (char *rname, int p_type, char *src)
9592 {
9593   switch (p_type)
9594     {
9595     case IPOINTER:
9596     case POINTER:
9597       if (*src=='@')
9598         {
9599           MOVA (src);
9600           emitcode ("mov", "@%s,a", rname);
9601         }
9602       else
9603         emitcode ("mov", "@%s,%s", rname, src);
9604       break;
9605
9606     case PPOINTER:
9607       MOVA (src);
9608       emitcode ("movx", "@%s,a", rname);
9609       break;
9610
9611     case FPOINTER:
9612       MOVA (src);
9613       emitcode ("movx", "@dptr,a");
9614       break;
9615
9616     case GPOINTER:
9617       MOVA (src);
9618       emitcode ("lcall", "__gptrput");
9619       break;
9620     }
9621 }
9622
9623 /*-----------------------------------------------------------------*/
9624 /* genUnpackBits - generates code for unpacking bits               */
9625 /*-----------------------------------------------------------------*/
9626 static void
9627 genUnpackBits (operand * result, char *rname, int ptype)
9628 {
9629   int offset = 0;       /* result byte offset */
9630   int rsize;            /* result size */
9631   int rlen = 0;         /* remaining bitfield length */
9632   sym_link *etype;      /* bitfield type information */
9633   int blen;             /* bitfield length */
9634   int bstr;             /* bitfield starting bit within byte */
9635
9636   D(emitcode (";     genUnpackBits",""));
9637
9638   etype = getSpec (operandType (result));
9639   rsize = getSize (operandType (result));
9640   blen = SPEC_BLEN (etype);
9641   bstr = SPEC_BSTR (etype);
9642
9643   /* If the bitfield length is less than a byte */
9644   if (blen < 8)
9645     {
9646       emitPtrByteGet (rname, ptype, FALSE);
9647       AccRsh (bstr);
9648       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
9649       aopPut (AOP (result), "a", offset++);
9650       goto finish;
9651     }
9652
9653   /* Bit field did not fit in a byte. Copy all
9654      but the partial byte at the end.  */
9655   for (rlen=blen;rlen>=8;rlen-=8)
9656     {
9657       emitPtrByteGet (rname, ptype, FALSE);
9658       aopPut (AOP (result), "a", offset++);
9659       if (rlen>8)
9660         emitcode ("inc", "%s", rname);
9661     }
9662
9663   /* Handle the partial byte at the end */
9664   if (rlen)
9665     {
9666       emitPtrByteGet (rname, ptype, FALSE);
9667       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
9668       aopPut (AOP (result), "a", offset++);
9669     }
9670
9671 finish:
9672   if (offset < rsize)
9673     {
9674       rsize -= offset;
9675       while (rsize--)
9676         aopPut (AOP (result), zero, offset++);
9677     }
9678 }
9679
9680
9681 /*-----------------------------------------------------------------*/
9682 /* genDataPointerGet - generates code when ptr offset is known     */
9683 /*-----------------------------------------------------------------*/
9684 static void
9685 genDataPointerGet (operand * left,
9686                    operand * result,
9687                    iCode * ic)
9688 {
9689   char *l;
9690   char buff[256];
9691   int size, offset = 0;
9692   aopOp (result, ic, TRUE, FALSE);
9693
9694   /* get the string representation of the name */
9695   l = aopGet (AOP (left), 0, FALSE, TRUE, NULL);
9696   size = AOP_SIZE (result);
9697   _startLazyDPSEvaluation ();
9698   while (size--)
9699     {
9700         if (offset)
9701         {
9702             SNPRINTF (buff, sizeof(buff),
9703                       "(%s + %d)", l + 1, offset);
9704         }
9705         else
9706         {
9707             SNPRINTF (buff, sizeof(buff),
9708                       "%s", l + 1);
9709         }
9710       aopPut (AOP (result), buff, offset++);
9711     }
9712   _endLazyDPSEvaluation ();
9713
9714   freeAsmop (left, NULL, ic, TRUE);
9715   freeAsmop (result, NULL, ic, TRUE);
9716 }
9717
9718 /*-----------------------------------------------------------------*/
9719 /* genNearPointerGet - emitcode for near pointer fetch             */
9720 /*-----------------------------------------------------------------*/
9721 static void
9722 genNearPointerGet (operand * left,
9723                    operand * result,
9724                    iCode * ic,
9725                    iCode *pi)
9726 {
9727   asmop *aop = NULL;
9728   regs *preg;
9729   char *rname;
9730   sym_link *rtype, *retype, *letype;
9731   sym_link *ltype = operandType (left);
9732   char buff[80];
9733
9734   rtype = operandType (result);
9735   retype = getSpec (rtype);
9736   letype = getSpec (ltype);
9737
9738   aopOp (left, ic, FALSE, FALSE);
9739
9740   /* if left is rematerialisable and
9741      result is not bitfield variable type and
9742      the left is pointer to data space i.e
9743      lower 128 bytes of space */
9744   if (AOP_TYPE (left) == AOP_IMMD &&
9745       !IS_BITFIELD (retype) &&
9746       !IS_BITFIELD (letype) &&
9747       DCL_TYPE (ltype) == POINTER)
9748     {
9749       genDataPointerGet (left, result, ic);
9750       return;
9751     }
9752
9753   /* if the value is already in a pointer register
9754      then don't need anything more */
9755   if (!AOP_INPREG (AOP (left)))
9756     {
9757       /* otherwise get a free pointer register */
9758       aop = newAsmop (0);
9759       preg = getFreePtr (ic, &aop, FALSE);
9760       emitcode ("mov", "%s,%s",
9761                 preg->name,
9762                 aopGet (AOP (left), 0, FALSE, TRUE, DP2_RESULT_REG));
9763       rname = preg->name;
9764     }
9765   else
9766     rname = aopGet (AOP (left), 0, FALSE, FALSE, DP2_RESULT_REG);
9767
9768   freeAsmop (left, NULL, ic, TRUE);
9769   aopOp (result, ic, FALSE, FALSE);
9770
9771   /* if bitfield then unpack the bits */
9772   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9773     genUnpackBits (result, rname, POINTER);
9774   else
9775     {
9776       /* we have can just get the values */
9777       int size = AOP_SIZE (result);
9778       int offset = 0;
9779
9780       while (size--)
9781         {
9782           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9783             {
9784
9785               emitcode ("mov", "a,@%s", rname);
9786               aopPut (AOP (result), "a", offset);
9787             }
9788           else
9789             {
9790               SNPRINTF (buff, sizeof(buff), "@%s", rname);
9791               aopPut (AOP (result), buff, offset);
9792             }
9793           offset++;
9794           if (size || pi)
9795             {
9796                 emitcode ("inc", "%s", rname);
9797             }
9798         }
9799     }
9800
9801   /* now some housekeeping stuff */
9802   if (aop)
9803     {
9804       /* we had to allocate for this iCode */
9805       if (pi) { /* post increment present */
9806         aopPut(AOP ( left ),rname,0);
9807       }
9808       freeAsmop (NULL, aop, ic, TRUE);
9809     }
9810   else
9811     {
9812       /* we did not allocate which means left
9813          already in a pointer register, then
9814          if size > 0 && this could be used again
9815          we have to point it back to where it
9816          belongs */
9817       if (AOP_SIZE (result) > 1 &&
9818           !OP_SYMBOL (left)->remat &&
9819           (OP_SYMBOL (left)->liveTo > ic->seq ||
9820            ic->depth) &&
9821           !pi)
9822         {
9823           int size = AOP_SIZE (result) - 1;
9824           while (size--)
9825             emitcode ("dec", "%s", rname);
9826         }
9827     }
9828
9829   /* done */
9830   freeAsmop (result, NULL, ic, TRUE);
9831   if (pi) pi->generated = 1;
9832 }
9833
9834 /*-----------------------------------------------------------------*/
9835 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9836 /*-----------------------------------------------------------------*/
9837 static void
9838 genPagedPointerGet (operand * left,
9839                     operand * result,
9840                     iCode * ic,
9841                     iCode * pi)
9842 {
9843   asmop *aop = NULL;
9844   regs *preg;
9845   char *rname;
9846   sym_link *rtype, *retype, *letype;
9847
9848   rtype = operandType (result);
9849   retype = getSpec (rtype);
9850   letype = getSpec (operandType (left));
9851   aopOp (left, ic, FALSE, FALSE);
9852
9853   /* if the value is already in a pointer register
9854      then don't need anything more */
9855   if (!AOP_INPREG (AOP (left)))
9856     {
9857       /* otherwise get a free pointer register */
9858       aop = newAsmop (0);
9859       preg = getFreePtr (ic, &aop, FALSE);
9860       emitcode ("mov", "%s,%s",
9861                 preg->name,
9862                 aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9863       rname = preg->name;
9864     }
9865   else
9866     rname = aopGet (AOP (left), 0, FALSE, FALSE, NULL);
9867
9868   freeAsmop (left, NULL, ic, TRUE);
9869   aopOp (result, ic, FALSE, FALSE);
9870
9871   /* if bitfield then unpack the bits */
9872   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9873     genUnpackBits (result, rname, PPOINTER);
9874   else
9875     {
9876       /* we have can just get the values */
9877       int size = AOP_SIZE (result);
9878       int offset = 0;
9879
9880       while (size--)
9881         {
9882
9883           emitcode ("movx", "a,@%s", rname);
9884           aopPut (AOP (result), "a", offset);
9885
9886           offset++;
9887
9888           if (size || pi)
9889             emitcode ("inc", "%s", rname);
9890         }
9891     }
9892
9893   /* now some housekeeping stuff */
9894   if (aop)
9895     {
9896       /* we had to allocate for this iCode */
9897       if (pi) aopPut ( AOP (left), rname, 0);
9898       freeAsmop (NULL, aop, ic, TRUE);
9899     }
9900   else
9901     {
9902       /* we did not allocate which means left
9903          already in a pointer register, then
9904          if size > 0 && this could be used again
9905          we have to point it back to where it
9906          belongs */
9907       if (AOP_SIZE (result) > 1 &&
9908           !OP_SYMBOL (left)->remat &&
9909           (OP_SYMBOL (left)->liveTo > ic->seq ||
9910            ic->depth) &&
9911           !pi)
9912         {
9913           int size = AOP_SIZE (result) - 1;
9914           while (size--)
9915             emitcode ("dec", "%s", rname);
9916         }
9917     }
9918
9919   /* done */
9920   freeAsmop (result, NULL, ic, TRUE);
9921   if (pi) pi->generated = 1;
9922 }
9923
9924 /*-----------------------------------------------------------------*/
9925 /* genFarPointerGet - gget value from far space                    */
9926 /*-----------------------------------------------------------------*/
9927 static void
9928 genFarPointerGet (operand * left,
9929                   operand * result, iCode * ic, iCode *pi)
9930 {
9931     int size, offset, dopi=1;
9932   sym_link *retype = getSpec (operandType (result));
9933   sym_link *letype = getSpec (operandType (left));
9934   D (emitcode (";", "genFarPointerGet"););
9935
9936   aopOp (left, ic, FALSE, FALSE);
9937
9938   /* if the operand is already in dptr
9939      then we do nothing else we move the value to dptr */
9940   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
9941     {
9942       /* if this is remateriazable */
9943       if (AOP_TYPE (left) == AOP_IMMD)
9944         {
9945           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
9946         }
9947       else
9948         {
9949           /* we need to get it byte by byte */
9950           _startLazyDPSEvaluation ();
9951           if (AOP_TYPE (left) != AOP_DPTR)
9952             {
9953               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9954               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
9955               if (options.model == MODEL_FLAT24)
9956                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9957             }
9958           else
9959             {
9960               /* We need to generate a load to DPTR indirect through DPTR. */
9961               D (emitcode (";", "genFarPointerGet -- indirection special case."););
9962               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9963               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
9964               if (options.model == MODEL_FLAT24)
9965                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9966               emitcode ("pop", "dph");
9967               emitcode ("pop", "dpl");
9968               dopi =0;
9969             }
9970           _endLazyDPSEvaluation ();
9971         }
9972     }
9973   /* so dptr know contains the address */
9974   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
9975
9976   /* if bit then unpack */
9977   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
9978       if (AOP_INDPTRn(left)) {
9979           genSetDPTR(AOP(left)->aopu.dptr);
9980       }
9981       genUnpackBits (result, "dptr", FPOINTER);
9982       if (AOP_INDPTRn(left)) {
9983           genSetDPTR(0);
9984       }
9985   } else
9986     {
9987       size = AOP_SIZE (result);
9988       offset = 0;
9989
9990       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
9991           while (size--) {
9992               genSetDPTR(AOP(left)->aopu.dptr);
9993               emitcode ("movx", "a,@dptr");
9994               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9995                   emitcode ("inc", "dptr");
9996               genSetDPTR (0);
9997               aopPut (AOP (result), "a", offset++);
9998           }
9999       } else {
10000           _startLazyDPSEvaluation ();
10001           while (size--) {
10002               if (AOP_INDPTRn(left)) {
10003                   genSetDPTR(AOP(left)->aopu.dptr);
10004               } else {
10005                   genSetDPTR (0);
10006               }
10007               _flushLazyDPS ();
10008
10009               emitcode ("movx", "a,@dptr");
10010               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10011                   emitcode ("inc", "dptr");
10012
10013               aopPut (AOP (result), "a", offset++);
10014           }
10015           _endLazyDPSEvaluation ();
10016       }
10017     }
10018   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10019       if (!AOP_INDPTRn(left)) {
10020           _startLazyDPSEvaluation ();
10021           aopPut ( AOP (left), "dpl", 0);
10022           aopPut ( AOP (left), "dph", 1);
10023           if (options.model == MODEL_FLAT24)
10024               aopPut ( AOP (left), "dpx", 2);
10025           _endLazyDPSEvaluation ();
10026       }
10027     pi->generated = 1;
10028   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10029              AOP_SIZE(result) > 1 &&
10030              IS_SYMOP(left) &&
10031              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10032
10033       size = AOP_SIZE (result) - 1;
10034       if (AOP_INDPTRn(left)) {
10035           genSetDPTR(AOP(left)->aopu.dptr);
10036       }
10037       while (size--) emitcode ("lcall","__decdptr");
10038       if (AOP_INDPTRn(left)) {
10039           genSetDPTR(0);
10040       }
10041   }
10042
10043   freeAsmop (left, NULL, ic, TRUE);
10044   freeAsmop (result, NULL, ic, TRUE);
10045 }
10046
10047 /*-----------------------------------------------------------------*/
10048 /* genCodePointerGet - get value from code space                  */
10049 /*-----------------------------------------------------------------*/
10050 static void
10051 genCodePointerGet (operand * left,
10052                     operand * result, iCode * ic, iCode *pi)
10053 {
10054   int size, offset, dopi=1;
10055   sym_link *retype = getSpec (operandType (result));
10056
10057   aopOp (left, ic, FALSE, FALSE);
10058
10059   /* if the operand is already in dptr
10060      then we do nothing else we move the value to dptr */
10061   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10062     {
10063       /* if this is remateriazable */
10064       if (AOP_TYPE (left) == AOP_IMMD)
10065         {
10066           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
10067         }
10068       else
10069         {                       /* we need to get it byte by byte */
10070           _startLazyDPSEvaluation ();
10071           if (AOP_TYPE (left) != AOP_DPTR)
10072             {
10073               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
10074               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
10075               if (options.model == MODEL_FLAT24)
10076                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
10077             }
10078           else
10079             {
10080               /* We need to generate a load to DPTR indirect through DPTR. */
10081               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10082               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
10083               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
10084               if (options.model == MODEL_FLAT24)
10085                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
10086               emitcode ("pop", "dph");
10087               emitcode ("pop", "dpl");
10088               dopi=0;
10089             }
10090           _endLazyDPSEvaluation ();
10091         }
10092     }
10093   /* so dptr know contains the address */
10094   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10095
10096   /* if bit then unpack */
10097   if (IS_BITFIELD (retype)) {
10098       if (AOP_INDPTRn(left)) {
10099           genSetDPTR(AOP(left)->aopu.dptr);
10100       }
10101       genUnpackBits (result, "dptr", CPOINTER);
10102       if (AOP_INDPTRn(left)) {
10103           genSetDPTR(0);
10104       }
10105   } else
10106     {
10107       size = AOP_SIZE (result);
10108       offset = 0;
10109       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10110           while (size--) {
10111               genSetDPTR(AOP(left)->aopu.dptr);
10112               emitcode ("clr", "a");
10113               emitcode ("movc", "a,@a+dptr");
10114               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10115                   emitcode ("inc", "dptr");
10116               genSetDPTR (0);
10117               aopPut (AOP (result), "a", offset++);
10118           }
10119       } else {
10120           _startLazyDPSEvaluation ();
10121           while (size--)
10122               {
10123                   if (AOP_INDPTRn(left)) {
10124                       genSetDPTR(AOP(left)->aopu.dptr);
10125                   } else {
10126                       genSetDPTR (0);
10127                   }
10128                   _flushLazyDPS ();
10129
10130                   emitcode ("clr", "a");
10131                   emitcode ("movc", "a,@a+dptr");
10132                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10133                       emitcode ("inc", "dptr");
10134                   aopPut (AOP (result), "a", offset++);
10135               }
10136           _endLazyDPSEvaluation ();
10137       }
10138     }
10139   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10140       if (!AOP_INDPTRn(left)) {
10141           _startLazyDPSEvaluation ();
10142
10143           aopPut ( AOP (left), "dpl", 0);
10144           aopPut ( AOP (left), "dph", 1);
10145           if (options.model == MODEL_FLAT24)
10146               aopPut ( AOP (left), "dpx", 2);
10147
10148           _endLazyDPSEvaluation ();
10149       }
10150       pi->generated = 1;
10151   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10152              AOP_SIZE(result) > 1 &&
10153              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10154
10155       size = AOP_SIZE (result) - 1;
10156       if (AOP_INDPTRn(left)) {
10157           genSetDPTR(AOP(left)->aopu.dptr);
10158       }
10159       while (size--) emitcode ("lcall","__decdptr");
10160       if (AOP_INDPTRn(left)) {
10161           genSetDPTR(0);
10162       }
10163   }
10164
10165   freeAsmop (left, NULL, ic, TRUE);
10166   freeAsmop (result, NULL, ic, TRUE);
10167 }
10168
10169 /*-----------------------------------------------------------------*/
10170 /* genGenPointerGet - gget value from generic pointer space        */
10171 /*-----------------------------------------------------------------*/
10172 static void
10173 genGenPointerGet (operand * left,
10174                   operand * result, iCode * ic, iCode * pi)
10175 {
10176   int size, offset;
10177   sym_link *retype = getSpec (operandType (result));
10178   sym_link *letype = getSpec (operandType (left));
10179
10180   D (emitcode (";", "genGenPointerGet "); );
10181
10182   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10183
10184   /* if the operand is already in dptr
10185      then we do nothing else we move the value to dptr */
10186   if (AOP_TYPE (left) != AOP_STR)
10187     {
10188       /* if this is remateriazable */
10189       if (AOP_TYPE (left) == AOP_IMMD)
10190         {
10191           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
10192           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10193             {
10194                 MOVB(aopGet(AOP (left), AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10195             }
10196             else
10197             {
10198                 emitcode ("mov", "b,#%d", pointerCode (retype));
10199             }
10200         }
10201       else
10202         {                       /* we need to get it byte by byte */
10203             _startLazyDPSEvaluation ();
10204             emitcode ("mov", "dpl,%s", aopGet (AOP(left),0,FALSE,FALSE,NULL));
10205             emitcode ("mov", "dph,%s", aopGet (AOP(left),1,FALSE,FALSE,NULL));
10206             if (options.model == MODEL_FLAT24) {
10207                 emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
10208                 emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,NULL));
10209             } else {
10210                 emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
10211             }
10212             _endLazyDPSEvaluation ();
10213         }
10214     }
10215
10216   /* so dptr-b now contains the address */
10217   _G.bInUse++;
10218   aopOp (result, ic, FALSE, TRUE);
10219   _G.bInUse--;
10220
10221   /* if bit then unpack */
10222   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10223   {
10224     genUnpackBits (result, "dptr", GPOINTER);
10225   }
10226   else
10227     {
10228         size = AOP_SIZE (result);
10229         offset = 0;
10230
10231         while (size--)
10232         {
10233             if (size)
10234             {
10235                 // Get two bytes at a time, results in _AP & A.
10236                 // dptr will be incremented ONCE by __gptrgetWord.
10237                 //
10238                 // Note: any change here must be coordinated
10239                 // with the implementation of __gptrgetWord
10240                 // in device/lib/_gptrget.c
10241                 emitcode ("lcall", "__gptrgetWord");
10242                 aopPut (AOP (result), DP2_RESULT_REG, offset++);
10243                 aopPut (AOP (result), "a", offset++);
10244                 size--;
10245             }
10246             else
10247             {
10248                 // Only one byte to get.
10249                 emitcode ("lcall", "__gptrget");
10250                 aopPut (AOP (result), "a", offset++);
10251             }
10252
10253             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10254             {
10255                 emitcode ("inc", "dptr");
10256             }
10257         }
10258     }
10259
10260   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10261     _startLazyDPSEvaluation ();
10262
10263     aopPut ( AOP (left), "dpl", 0);
10264     aopPut ( AOP (left), "dph", 1);
10265     if (options.model == MODEL_FLAT24) {
10266         aopPut ( AOP (left), "dpx", 2);
10267         aopPut ( AOP (left), "b", 3);
10268     } else  aopPut ( AOP (left), "b", 2);
10269
10270     _endLazyDPSEvaluation ();
10271
10272     pi->generated = 1;
10273   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10274              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10275
10276       size = AOP_SIZE (result) - 1;
10277       while (size--) emitcode ("lcall","__decdptr");
10278   }
10279
10280   freeAsmop (left, NULL, ic, TRUE);
10281   freeAsmop (result, NULL, ic, TRUE);
10282 }
10283
10284 /*-----------------------------------------------------------------*/
10285 /* genPointerGet - generate code for pointer get                   */
10286 /*-----------------------------------------------------------------*/
10287 static void
10288 genPointerGet (iCode * ic, iCode *pi)
10289 {
10290   operand *left, *result;
10291   sym_link *type, *etype;
10292   int p_type;
10293
10294   D (emitcode (";", "genPointerGet ");
10295     );
10296
10297   left = IC_LEFT (ic);
10298   result = IC_RESULT (ic);
10299
10300   /* depending on the type of pointer we need to
10301      move it to the correct pointer register */
10302   type = operandType (left);
10303   etype = getSpec (type);
10304   /* if left is of type of pointer then it is simple */
10305   if (IS_PTR (type) && !IS_FUNC (type->next))
10306     p_type = DCL_TYPE (type);
10307   else
10308     {
10309       /* we have to go by the storage class */
10310       p_type = PTR_TYPE (SPEC_OCLS (etype));
10311     }
10312   /* special case when cast remat */
10313   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10314       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode)) {
10315           left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10316           type = operandType (left);
10317           p_type = DCL_TYPE (type);
10318   }
10319   /* now that we have the pointer type we assign
10320      the pointer values */
10321   switch (p_type)
10322     {
10323
10324     case POINTER:
10325     case IPOINTER:
10326       genNearPointerGet (left, result, ic, pi);
10327       break;
10328
10329     case PPOINTER:
10330       genPagedPointerGet (left, result, ic, pi);
10331       break;
10332
10333     case FPOINTER:
10334       genFarPointerGet (left, result, ic, pi);
10335       break;
10336
10337     case CPOINTER:
10338       genCodePointerGet (left, result, ic, pi);
10339       break;
10340
10341     case GPOINTER:
10342       genGenPointerGet (left, result, ic, pi);
10343       break;
10344     }
10345
10346 }
10347
10348 /*-----------------------------------------------------------------*/
10349 /* genPackBits - generates code for packed bit storage             */
10350 /*-----------------------------------------------------------------*/
10351 static void
10352 genPackBits (sym_link * etype,
10353              operand * right,
10354              char *rname, int p_type)
10355 {
10356   int offset = 0;       /* source byte offset */
10357   int rlen = 0;         /* remaining bitfield length */
10358   int blen;             /* bitfield length */
10359   int bstr;             /* bitfield starting bit within byte */
10360   int litval;           /* source literal value (if AOP_LIT) */
10361   unsigned char mask;   /* bitmask within current byte */
10362
10363   D(emitcode (";     genPackBits",""));
10364
10365   blen = SPEC_BLEN (etype);
10366   bstr = SPEC_BSTR (etype);
10367
10368   /* If the bitfield length is less than a byte */
10369   if (blen < 8)
10370     {
10371       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10372               (unsigned char) (0xFF >> (8 - bstr)));
10373
10374       if (AOP_TYPE (right) == AOP_LIT)
10375         {
10376           /* Case with a bitfield length <8 and literal source
10377           */
10378           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10379           litval <<= bstr;
10380           litval &= (~mask) & 0xff;
10381           emitPtrByteGet (rname, p_type, FALSE);
10382           if ((mask|litval)!=0xff)
10383             emitcode ("anl","a,#!constbyte", mask);
10384           if (litval)
10385             emitcode ("orl","a,#!constbyte", litval);
10386         }
10387       else
10388         {
10389           if ((blen==1) && (p_type!=GPOINTER))
10390             {
10391               /* Case with a bitfield length == 1 and no generic pointer
10392               */
10393               if (AOP_TYPE (right) == AOP_CRY)
10394                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10395               else
10396                 {
10397                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
10398                   emitcode ("rrc","a");
10399                 }
10400               emitPtrByteGet (rname, p_type, FALSE);
10401               emitcode ("mov","acc.%d,c",bstr);
10402             }
10403           else
10404             {
10405               /* Case with a bitfield length < 8 and arbitrary source
10406               */
10407               MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
10408               /* shift and mask source value */
10409               AccLsh (bstr);
10410               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
10411
10412               /* transfer A to B and get next byte */
10413               emitPtrByteGet (rname, p_type, TRUE);
10414
10415               emitcode ("anl", "a,#!constbyte", mask);
10416               emitcode ("orl", "a,b");
10417               if (p_type == GPOINTER)
10418                 emitcode ("pop", "b");
10419            }
10420         }
10421
10422       emitPtrByteSet (rname, p_type, "a");
10423       return;
10424     }
10425
10426   /* Bit length is greater than 7 bits. In this case, copy  */
10427   /* all except the partial byte at the end                 */
10428   for (rlen=blen;rlen>=8;rlen-=8)
10429     {
10430       emitPtrByteSet (rname, p_type,
10431                       aopGet (AOP (right), offset++, FALSE, TRUE, NULL) );
10432       if (rlen>8)
10433         emitcode ("inc", "%s", rname);
10434     }
10435
10436   /* If there was a partial byte at the end */
10437   if (rlen)
10438     {
10439       mask = (((unsigned char) -1 << rlen) & 0xff);
10440
10441       if (AOP_TYPE (right) == AOP_LIT)
10442         {
10443           /* Case with partial byte and literal source
10444           */
10445           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10446           litval >>= (blen-rlen);
10447           litval &= (~mask) & 0xff;
10448           emitPtrByteGet (rname, p_type, FALSE);
10449           if ((mask|litval)!=0xff)
10450             emitcode ("anl","a,#!constbyte", mask);
10451           if (litval)
10452             emitcode ("orl","a,#!constbyte", litval);
10453         }
10454       else
10455         {
10456           /* Case with partial byte and arbitrary source
10457           */
10458           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10459           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
10460
10461           /* transfer A to B and get next byte */
10462           emitPtrByteGet (rname, p_type, TRUE);
10463
10464           emitcode ("anl", "a,#!constbyte", mask);
10465           emitcode ("orl", "a,b");
10466           if (p_type == GPOINTER)
10467             emitcode ("pop", "b");
10468         }
10469       emitPtrByteSet (rname, p_type, "a");
10470     }
10471
10472 }
10473
10474
10475 /*-----------------------------------------------------------------*/
10476 /* genDataPointerSet - remat pointer to data space                 */
10477 /*-----------------------------------------------------------------*/
10478 static void
10479 genDataPointerSet (operand * right,
10480                    operand * result,
10481                    iCode * ic)
10482 {
10483   int size, offset = 0;
10484   char *l, buff[256];
10485
10486   aopOp (right, ic, FALSE, FALSE);
10487
10488   l = aopGet (AOP (result), 0, FALSE, TRUE, NULL);
10489   size = AOP_SIZE (right);
10490   while (size--)
10491     {
10492       if (offset)
10493         {
10494             SNPRINTF (buff, sizeof(buff), "(%s + %d)", l + 1, offset);
10495         }
10496       else
10497         {
10498             SNPRINTF (buff, sizeof(buff), "%s", l + 1);
10499         }
10500
10501       emitcode ("mov", "%s,%s", buff,
10502                 aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10503     }
10504
10505   freeAsmop (right, NULL, ic, TRUE);
10506   freeAsmop (result, NULL, ic, TRUE);
10507 }
10508
10509 /*-----------------------------------------------------------------*/
10510 /* genNearPointerSet - emitcode for near pointer put                */
10511 /*-----------------------------------------------------------------*/
10512 static void
10513 genNearPointerSet (operand * right,
10514                    operand * result,
10515                    iCode * ic,
10516                    iCode * pi)
10517 {
10518   asmop *aop = NULL;
10519   char *rname, *l;
10520   sym_link *retype, *letype;
10521   sym_link *ptype = operandType (result);
10522
10523   retype = getSpec (operandType (right));
10524   letype = getSpec (ptype);
10525
10526   aopOp (result, ic, FALSE, FALSE);
10527
10528   /* if the result is rematerializable &
10529      in data space & not a bit variable */
10530   if (AOP_TYPE (result) == AOP_IMMD &&
10531       DCL_TYPE (ptype) == POINTER &&
10532       !IS_BITVAR (retype) &&
10533       !IS_BITVAR (letype))
10534     {
10535       genDataPointerSet (right, result, ic);
10536       return;
10537     }
10538
10539   /* if the value is already in a pointer register
10540      then don't need anything more */
10541   if (!AOP_INPREG (AOP (result)))
10542     {
10543       /* otherwise get a free pointer register */
10544       regs *preg;
10545
10546       aop = newAsmop (0);
10547       preg = getFreePtr (ic, &aop, FALSE);
10548       emitcode ("mov", "%s,%s",
10549                 preg->name,
10550                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10551       rname = preg->name;
10552     }
10553   else
10554     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
10555
10556   aopOp (right, ic, FALSE, FALSE);
10557
10558   /* if bitfield then unpack the bits */
10559   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10560     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10561   else
10562     {
10563       /* we have can just get the values */
10564       int size = AOP_SIZE (right);
10565       int offset = 0;
10566
10567       while (size--)
10568         {
10569           l = aopGet (AOP (right), offset, FALSE, TRUE, NULL);
10570           if (*l == '@')
10571             {
10572               MOVA (l);
10573               emitcode ("mov", "@%s,a", rname);
10574             }
10575           else
10576             emitcode ("mov", "@%s,%s", rname, l);
10577           if (size || pi)
10578             emitcode ("inc", "%s", rname);
10579           offset++;
10580         }
10581     }
10582
10583   /* now some housekeeping stuff */
10584   if (aop)
10585     {
10586       /* we had to allocate for this iCode */
10587       if (pi) aopPut (AOP (result),rname,0);
10588       freeAsmop (NULL, aop, ic, TRUE);
10589     }
10590   else
10591     {
10592       /* we did not allocate which means left
10593          already in a pointer register, then
10594          if size > 0 && this could be used again
10595          we have to point it back to where it
10596          belongs */
10597       if (AOP_SIZE (right) > 1 &&
10598           !OP_SYMBOL (result)->remat &&
10599           (OP_SYMBOL (result)->liveTo > ic->seq ||
10600            ic->depth) &&
10601           !pi)
10602         {
10603           int size = AOP_SIZE (right) - 1;
10604           while (size--)
10605             emitcode ("dec", "%s", rname);
10606         }
10607     }
10608
10609   /* done */
10610   if (pi) pi->generated = 1;
10611   freeAsmop (result, NULL, ic, TRUE);
10612   freeAsmop (right, NULL, ic, TRUE);
10613
10614
10615 }
10616
10617 /*-----------------------------------------------------------------*/
10618 /* genPagedPointerSet - emitcode for Paged pointer put             */
10619 /*-----------------------------------------------------------------*/
10620 static void
10621 genPagedPointerSet (operand * right,
10622                     operand * result,
10623                     iCode * ic,
10624                     iCode *pi)
10625 {
10626   asmop *aop = NULL;
10627   char *rname;
10628   sym_link *retype, *letype;
10629
10630   retype = getSpec (operandType (right));
10631   letype = getSpec (operandType (result));
10632
10633   aopOp (result, ic, FALSE, FALSE);
10634
10635   /* if the value is already in a pointer register
10636      then don't need anything more */
10637   if (!AOP_INPREG (AOP (result)))
10638     {
10639       /* otherwise get a free pointer register */
10640       regs *preg;
10641
10642       aop = newAsmop (0);
10643       preg = getFreePtr (ic, &aop, FALSE);
10644       emitcode ("mov", "%s,%s",
10645                 preg->name,
10646                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10647       rname = preg->name;
10648     }
10649   else
10650     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
10651
10652   aopOp (right, ic, FALSE, FALSE);
10653
10654   /* if bitfield then unpack the bits */
10655   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10656     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10657   else
10658     {
10659       /* we have can just get the values */
10660       int size = AOP_SIZE (right);
10661       int offset = 0;
10662
10663       while (size--)
10664         {
10665           MOVA (aopGet (AOP (right), offset, FALSE, TRUE, NULL));
10666
10667           emitcode ("movx", "@%s,a", rname);
10668
10669           if (size || pi)
10670             emitcode ("inc", "%s", rname);
10671
10672           offset++;
10673         }
10674     }
10675
10676   /* now some housekeeping stuff */
10677   if (aop)
10678     {
10679       if (pi) aopPut (AOP (result),rname,0);
10680       /* we had to allocate for this iCode */
10681       freeAsmop (NULL, aop, ic, TRUE);
10682     }
10683   else
10684     {
10685       /* we did not allocate which means left
10686          already in a pointer register, then
10687          if size > 0 && this could be used again
10688          we have to point it back to where it
10689          belongs */
10690       if (AOP_SIZE (right) > 1 &&
10691           !OP_SYMBOL (result)->remat &&
10692           (OP_SYMBOL (result)->liveTo > ic->seq ||
10693            ic->depth) &&
10694           !pi)
10695         {
10696           int size = AOP_SIZE (right) - 1;
10697           while (size--)
10698             emitcode ("dec", "%s", rname);
10699         }
10700     }
10701
10702   /* done */
10703   if (pi) pi->generated = 1;
10704   freeAsmop (result, NULL, ic, TRUE);
10705   freeAsmop (right, NULL, ic, TRUE);
10706
10707
10708 }
10709
10710 /*-----------------------------------------------------------------*/
10711 /* genFarPointerSet - set value from far space                     */
10712 /*-----------------------------------------------------------------*/
10713 static void
10714 genFarPointerSet (operand * right,
10715                   operand * result, iCode * ic, iCode *pi)
10716 {
10717   int size, offset, dopi=1;
10718   sym_link *retype = getSpec (operandType (right));
10719   sym_link *letype = getSpec (operandType (result));
10720
10721   aopOp (result, ic, FALSE, FALSE);
10722
10723   /* if the operand is already in dptr
10724      then we do nothing else we move the value to dptr */
10725   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
10726     {
10727       /* if this is remateriazable */
10728       if (AOP_TYPE (result) == AOP_IMMD)
10729         emitcode ("mov", "dptr,%s",
10730                   aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10731       else
10732         {
10733           /* we need to get it byte by byte */
10734           _startLazyDPSEvaluation ();
10735           if (AOP_TYPE (result) != AOP_DPTR)
10736             {
10737               emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10738               emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10739               if (options.model == MODEL_FLAT24)
10740                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10741             }
10742           else
10743             {
10744               /* We need to generate a load to DPTR indirect through DPTR. */
10745               D (emitcode (";", "genFarPointerSet -- indirection special case."););
10746
10747               emitcode ("push", "%s", aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10748               emitcode ("push", "%s", aopGet (AOP (result), 1, FALSE, TRUE, NULL));
10749               if (options.model == MODEL_FLAT24)
10750                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10751               emitcode ("pop", "dph");
10752               emitcode ("pop", "dpl");
10753               dopi=0;
10754             }
10755           _endLazyDPSEvaluation ();
10756         }
10757     }
10758   /* so dptr know contains the address */
10759   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
10760
10761   /* if bit then unpack */
10762   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10763       if (AOP_INDPTRn(result)) {
10764           genSetDPTR(AOP(result)->aopu.dptr);
10765       }
10766       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10767       if (AOP_INDPTRn(result)) {
10768           genSetDPTR(0);
10769       }
10770   } else {
10771       size = AOP_SIZE (right);
10772       offset = 0;
10773       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
10774           while (size--) {
10775               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10776
10777               genSetDPTR(AOP(result)->aopu.dptr);
10778               emitcode ("movx", "@dptr,a");
10779               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10780                   emitcode ("inc", "dptr");
10781               genSetDPTR (0);
10782           }
10783       } else {
10784           _startLazyDPSEvaluation ();
10785           while (size--) {
10786               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10787
10788               if (AOP_INDPTRn(result)) {
10789                   genSetDPTR(AOP(result)->aopu.dptr);
10790               } else {
10791                   genSetDPTR (0);
10792               }
10793               _flushLazyDPS ();
10794
10795               emitcode ("movx", "@dptr,a");
10796               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10797                   emitcode ("inc", "dptr");
10798           }
10799           _endLazyDPSEvaluation ();
10800       }
10801   }
10802
10803   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
10804       if (!AOP_INDPTRn(result)) {
10805           _startLazyDPSEvaluation ();
10806
10807           aopPut (AOP(result),"dpl",0);
10808           aopPut (AOP(result),"dph",1);
10809           if (options.model == MODEL_FLAT24)
10810               aopPut (AOP(result),"dpx",2);
10811
10812           _endLazyDPSEvaluation ();
10813       }
10814       pi->generated=1;
10815   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
10816              AOP_SIZE(right) > 1 &&
10817              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10818
10819       size = AOP_SIZE (right) - 1;
10820       if (AOP_INDPTRn(result)) {
10821           genSetDPTR(AOP(result)->aopu.dptr);
10822       }
10823       while (size--) emitcode ("lcall","__decdptr");
10824       if (AOP_INDPTRn(result)) {
10825           genSetDPTR(0);
10826       }
10827   }
10828   freeAsmop (result, NULL, ic, TRUE);
10829   freeAsmop (right, NULL, ic, TRUE);
10830 }
10831
10832 /*-----------------------------------------------------------------*/
10833 /* genGenPointerSet - set value from generic pointer space         */
10834 /*-----------------------------------------------------------------*/
10835 static void
10836 genGenPointerSet (operand * right,
10837                   operand * result, iCode * ic, iCode *pi)
10838 {
10839   int size, offset;
10840   sym_link *retype = getSpec (operandType (right));
10841   sym_link *letype = getSpec (operandType (result));
10842
10843   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
10844
10845   /* if the operand is already in dptr
10846      then we do nothing else we move the value to dptr */
10847   if (AOP_TYPE (result) != AOP_STR)
10848     {
10849       _startLazyDPSEvaluation ();
10850       /* if this is remateriazable */
10851       if (AOP_TYPE (result) == AOP_IMMD)
10852         {
10853           emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10854           if (AOP(result)->aopu.aop_immd.from_cast_remat)
10855           {
10856               MOVB(aopGet(AOP (result), AOP_SIZE(result)-1, FALSE, FALSE, NULL));
10857           }
10858           else
10859           {
10860               emitcode ("mov",
10861                         "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10862           }
10863         }
10864       else
10865         {                       /* we need to get it byte by byte */
10866           emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10867           emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10868           if (options.model == MODEL_FLAT24) {
10869             emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10870             emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, NULL));
10871           } else {
10872             emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10873           }
10874         }
10875       _endLazyDPSEvaluation ();
10876     }
10877   /* so dptr + b now contains the address */
10878   _G.bInUse++;
10879   aopOp (right, ic, FALSE, TRUE);
10880   _G.bInUse--;
10881
10882
10883   /* if bit then unpack */
10884   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10885     {
10886         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10887     }
10888   else
10889     {
10890         size = AOP_SIZE (right);
10891         offset = 0;
10892
10893         _startLazyDPSEvaluation ();
10894         while (size--)
10895         {
10896             if (size)
10897             {
10898                 // Set two bytes at a time, passed in _AP & A.
10899                 // dptr will be incremented ONCE by __gptrputWord.
10900                 //
10901                 // Note: any change here must be coordinated
10902                 // with the implementation of __gptrputWord
10903                 // in device/lib/_gptrput.c
10904                 emitcode("mov", "_ap, %s",
10905                          aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10906                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10907
10908                 genSetDPTR (0);
10909                 _flushLazyDPS ();
10910                 emitcode ("lcall", "__gptrputWord");
10911                 size--;
10912             }
10913             else
10914             {
10915                 // Only one byte to put.
10916                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10917
10918                 genSetDPTR (0);
10919                 _flushLazyDPS ();
10920                 emitcode ("lcall", "__gptrput");
10921             }
10922
10923             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
10924             {
10925                 emitcode ("inc", "dptr");
10926             }
10927         }
10928         _endLazyDPSEvaluation ();
10929     }
10930
10931   if (pi && AOP_TYPE (result) != AOP_IMMD) {
10932       _startLazyDPSEvaluation ();
10933
10934       aopPut (AOP(result),"dpl",0);
10935       aopPut (AOP(result),"dph",1);
10936       if (options.model == MODEL_FLAT24) {
10937           aopPut (AOP(result),"dpx",2);
10938           aopPut (AOP(result),"b",3);
10939       } else {
10940           aopPut (AOP(result),"b",2);
10941       }
10942       _endLazyDPSEvaluation ();
10943
10944       pi->generated=1;
10945   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
10946              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10947
10948       size = AOP_SIZE (right) - 1;
10949       while (size--) emitcode ("lcall","__decdptr");
10950   }
10951   freeAsmop (result, NULL, ic, TRUE);
10952   freeAsmop (right, NULL, ic, TRUE);
10953 }
10954
10955 /*-----------------------------------------------------------------*/
10956 /* genPointerSet - stores the value into a pointer location        */
10957 /*-----------------------------------------------------------------*/
10958 static void
10959 genPointerSet (iCode * ic, iCode *pi)
10960 {
10961   operand *right, *result;
10962   sym_link *type, *etype;
10963   int p_type;
10964
10965   D (emitcode (";", "genPointerSet "););
10966
10967   right = IC_RIGHT (ic);
10968   result = IC_RESULT (ic);
10969
10970   /* depending on the type of pointer we need to
10971      move it to the correct pointer register */
10972   type = operandType (result);
10973   etype = getSpec (type);
10974   /* if left is of type of pointer then it is simple */
10975   if (IS_PTR (type) && !IS_FUNC (type->next))
10976     {
10977       p_type = DCL_TYPE (type);
10978     }
10979   else
10980     {
10981       /* we have to go by the storage class */
10982       p_type = PTR_TYPE (SPEC_OCLS (etype));
10983     }
10984   /* special case when cast remat */
10985   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10986       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10987           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10988           type = operandType (result);
10989           p_type = DCL_TYPE (type);
10990   }
10991
10992   /* now that we have the pointer type we assign
10993      the pointer values */
10994   switch (p_type)
10995     {
10996
10997     case POINTER:
10998     case IPOINTER:
10999       genNearPointerSet (right, result, ic, pi);
11000       break;
11001
11002     case PPOINTER:
11003       genPagedPointerSet (right, result, ic, pi);
11004       break;
11005
11006     case FPOINTER:
11007       genFarPointerSet (right, result, ic, pi);
11008       break;
11009
11010     case GPOINTER:
11011       genGenPointerSet (right, result, ic, pi);
11012       break;
11013
11014     default:
11015       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11016               "genPointerSet: illegal pointer type");
11017     }
11018
11019 }
11020
11021 /*-----------------------------------------------------------------*/
11022 /* genIfx - generate code for Ifx statement                        */
11023 /*-----------------------------------------------------------------*/
11024 static void
11025 genIfx (iCode * ic, iCode * popIc)
11026 {
11027   operand *cond = IC_COND (ic);
11028   int isbit = 0;
11029
11030   D (emitcode (";", "genIfx "););
11031
11032   aopOp (cond, ic, FALSE, FALSE);
11033
11034   /* get the value into acc */
11035   if (AOP_TYPE (cond) != AOP_CRY)
11036     {
11037         toBoolean (cond);
11038     }
11039   else
11040     {
11041         isbit = 1;
11042     }
11043
11044   /* the result is now in the accumulator */
11045   freeAsmop (cond, NULL, ic, TRUE);
11046
11047   /* if there was something to be popped then do it */
11048   if (popIc)
11049     genIpop (popIc);
11050
11051   /* if the condition is  a bit variable */
11052   if (isbit && IS_ITEMP (cond) &&
11053       SPIL_LOC (cond))
11054     {
11055         genIfxJump (ic, SPIL_LOC (cond)->rname);
11056     }
11057   else if (isbit && !IS_ITEMP (cond))
11058     {
11059         genIfxJump (ic, OP_SYMBOL (cond)->rname);
11060     }
11061   else
11062     {
11063         genIfxJump (ic, "a");
11064     }
11065
11066   ic->generated = 1;
11067 }
11068
11069 /*-----------------------------------------------------------------*/
11070 /* genAddrOf - generates code for address of                       */
11071 /*-----------------------------------------------------------------*/
11072 static void
11073 genAddrOf (iCode * ic)
11074 {
11075   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11076   int size, offset;
11077
11078   D (emitcode (";", "genAddrOf ");
11079     );
11080
11081   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11082
11083   /* if the operand is on the stack then we
11084      need to get the stack offset of this
11085      variable */
11086   if (sym->onStack) {
11087
11088       /* if 10 bit stack */
11089       if (options.stack10bit) {
11090           char buff[10];
11091           int  offset;
11092
11093           tsprintf(buff, sizeof(buff),
11094                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11095           /* if it has an offset then we need to compute it */
11096 /*        emitcode ("subb", "a,#!constbyte", */
11097 /*                  -((sym->stack < 0) ? */
11098 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11099 /*                    ((short) sym->stack)) & 0xff); */
11100 /*        emitcode ("mov","b,a"); */
11101 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11102 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11103 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11104           if (sym->stack) {
11105               emitcode ("mov", "a,_bpx");
11106               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11107                                              ((char) (sym->stack - _G.nRegsSaved)) :
11108                                              ((char) sym->stack )) & 0xff);
11109               emitcode ("mov", "b,a");
11110               emitcode ("mov", "a,_bpx+1");
11111
11112               offset = (((sym->stack < 0) ?
11113                          ((short) (sym->stack - _G.nRegsSaved)) :
11114                          ((short) sym->stack )) >> 8) & 0xff;
11115
11116               emitcode ("addc","a,#!constbyte", offset);
11117
11118               aopPut (AOP (IC_RESULT (ic)), "b", 0);
11119               aopPut (AOP (IC_RESULT (ic)), "a", 1);
11120               aopPut (AOP (IC_RESULT (ic)), buff, 2);
11121           } else {
11122               /* we can just move _bp */
11123               aopPut (AOP (IC_RESULT (ic)), "_bpx", 0);
11124               aopPut (AOP (IC_RESULT (ic)), "_bpx+1", 1);
11125               aopPut (AOP (IC_RESULT (ic)), buff, 2);
11126           }
11127       } else {
11128           /* if it has an offset then we need to compute it */
11129           if (sym->stack) {
11130               emitcode ("mov", "a,_bp");
11131               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11132               aopPut (AOP (IC_RESULT (ic)), "a", 0);
11133           } else {
11134               /* we can just move _bp */
11135               aopPut (AOP (IC_RESULT (ic)), "_bp", 0);
11136           }
11137           /* fill the result with zero */
11138           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11139
11140
11141           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11142               fprintf (stderr,
11143                        "*** warning: pointer to stack var truncated.\n");
11144           }
11145
11146           offset = 1;
11147           while (size--) {
11148               aopPut (AOP (IC_RESULT (ic)), zero, offset++);
11149           }
11150       }
11151       goto release;
11152   }
11153
11154   /* object not on stack then we need the name */
11155   size = AOP_SIZE (IC_RESULT (ic));
11156   offset = 0;
11157
11158   while (size--)
11159     {
11160       char s[SDCC_NAME_MAX];
11161       if (offset) {
11162           switch (offset) {
11163           case 1:
11164               tsprintf(s, sizeof(s), "#!his",sym->rname);
11165               break;
11166           case 2:
11167               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11168               break;
11169           case 3:
11170               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11171               break;
11172           default: /* should not need this (just in case) */
11173               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11174                        sym->rname,
11175                        offset * 8);
11176           }
11177       }
11178       else
11179       {
11180           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11181       }
11182
11183       aopPut (AOP (IC_RESULT (ic)), s, offset++);
11184     }
11185
11186 release:
11187   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11188
11189 }
11190
11191 #if 0 // obsolete, and buggy for != xdata
11192 /*-----------------------------------------------------------------*/
11193 /* genArrayInit - generates code for address of                       */
11194 /*-----------------------------------------------------------------*/
11195 static void
11196 genArrayInit (iCode * ic)
11197 {
11198     literalList *iLoop;
11199     int         ix, count;
11200     int         elementSize = 0, eIndex;
11201     unsigned    val, lastVal;
11202     sym_link    *type;
11203     operand     *left=IC_LEFT(ic);
11204
11205     D (emitcode (";", "genArrayInit "););
11206
11207     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11208
11209     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11210     {
11211         // Load immediate value into DPTR.
11212         emitcode("mov", "dptr, %s",
11213              aopGet(AOP(IC_LEFT(ic)), 0, TRUE, FALSE, NULL));
11214     }
11215     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11216     {
11217 #if 0
11218       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11219               "Unexpected operand to genArrayInit.\n");
11220       exit(1);
11221 #else
11222       // a regression because of SDCCcse.c:1.52
11223       emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
11224       emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
11225       if (options.model == MODEL_FLAT24)
11226         emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
11227 #endif
11228     }
11229
11230     type = operandType(IC_LEFT(ic));
11231
11232     if (type && type->next)
11233     {
11234         elementSize = getSize(type->next);
11235     }
11236     else
11237     {
11238         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11239                                 "can't determine element size in genArrayInit.\n");
11240         exit(1);
11241     }
11242
11243     iLoop = IC_ARRAYILIST(ic);
11244     lastVal = 0xffff;
11245
11246     while (iLoop)
11247     {
11248         bool firstpass = TRUE;
11249
11250         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11251                  iLoop->count, (int)iLoop->literalValue, elementSize);
11252
11253         ix = iLoop->count;
11254
11255         while (ix)
11256         {
11257             symbol *tlbl = NULL;
11258
11259             count = ix > 256 ? 256 : ix;
11260
11261             if (count > 1)
11262             {
11263                 tlbl = newiTempLabel (NULL);
11264                 if (firstpass || (count & 0xff))
11265                 {
11266                     emitcode("mov", "b, #!constbyte", count & 0xff);
11267                 }
11268
11269                 emitcode ("", "!tlabeldef", tlbl->key + 100);
11270             }
11271
11272             firstpass = FALSE;
11273
11274             for (eIndex = 0; eIndex < elementSize; eIndex++)
11275             {
11276                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11277                 if (val != lastVal)
11278                 {
11279                     emitcode("mov", "a, #!constbyte", val);
11280                     lastVal = val;
11281                 }
11282
11283                 emitcode("movx", "@dptr, a");
11284                 emitcode("inc", "dptr");
11285             }
11286
11287             if (count > 1)
11288             {
11289                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11290             }
11291
11292             ix -= count;
11293         }
11294
11295         iLoop = iLoop->next;
11296     }
11297
11298     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11299 }
11300 #endif
11301
11302 /*-----------------------------------------------------------------*/
11303 /* genFarFarAssign - assignment when both are in far space         */
11304 /*-----------------------------------------------------------------*/
11305 static void
11306 genFarFarAssign (operand * result, operand * right, iCode * ic)
11307 {
11308   int size = AOP_SIZE (right);
11309   int offset = 0;
11310   symbol *rSym = NULL;
11311
11312   if (size == 1)
11313   {
11314       /* quick & easy case. */
11315       D(emitcode(";","genFarFarAssign (1 byte case)"););
11316       MOVA(aopGet(AOP(right), 0, FALSE, FALSE, NULL));
11317       freeAsmop (right, NULL, ic, FALSE);
11318       /* now assign DPTR to result */
11319       _G.accInUse++;
11320       aopOp(result, ic, FALSE, FALSE);
11321       _G.accInUse--;
11322       aopPut(AOP(result), "a", 0);
11323       freeAsmop(result, NULL, ic, FALSE);
11324       return;
11325   }
11326
11327   /* See if we've got an underlying symbol to abuse. */
11328   if (IS_SYMOP(result) && OP_SYMBOL(result))
11329   {
11330       if (IS_TRUE_SYMOP(result))
11331       {
11332           rSym = OP_SYMBOL(result);
11333       }
11334       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11335       {
11336           rSym = OP_SYMBOL(result)->usl.spillLoc;
11337       }
11338   }
11339
11340   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11341   {
11342       /* We can use the '390 auto-toggle feature to good effect here. */
11343
11344       D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
11345       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11346       emitcode ("mov", "dptr,#%s", rSym->rname);
11347       /* DP2 = result, DP1 = right, DP1 is current. */
11348       while (size)
11349       {
11350           emitcode("movx", "a,@dptr");
11351           emitcode("movx", "@dptr,a");
11352           if (--size)
11353           {
11354                emitcode("inc", "dptr");
11355                emitcode("inc", "dptr");
11356           }
11357       }
11358       emitcode("mov", "dps,#0");
11359       freeAsmop (right, NULL, ic, FALSE);
11360 #if 0
11361 some alternative code for processors without auto-toggle
11362 no time to test now, so later well put in...kpb
11363         D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
11364         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11365         emitcode ("mov", "dptr,#%s", rSym->rname);
11366         /* DP2 = result, DP1 = right, DP1 is current. */
11367         while (size)
11368         {
11369           --size;
11370           emitcode("movx", "a,@dptr");
11371           if (size)
11372             emitcode("inc", "dptr");
11373           emitcode("inc", "dps");
11374           emitcode("movx", "@dptr,a");
11375           if (size)
11376             emitcode("inc", "dptr");
11377           emitcode("inc", "dps");
11378         }
11379         emitcode("mov", "dps,#0");
11380         freeAsmop (right, NULL, ic, FALSE);
11381 #endif
11382   }
11383   else
11384   {
11385       D (emitcode (";", "genFarFarAssign"););
11386       aopOp (result, ic, TRUE, TRUE);
11387
11388       _startLazyDPSEvaluation ();
11389
11390       while (size--)
11391         {
11392           aopPut (AOP (result),
11393                   aopGet (AOP (right), offset, FALSE, FALSE, NULL), offset);
11394           offset++;
11395         }
11396       _endLazyDPSEvaluation ();
11397       freeAsmop (result, NULL, ic, FALSE);
11398       freeAsmop (right, NULL, ic, FALSE);
11399   }
11400 }
11401
11402 /*-----------------------------------------------------------------*/
11403 /* genAssign - generate code for assignment                        */
11404 /*-----------------------------------------------------------------*/
11405 static void
11406 genAssign (iCode * ic)
11407 {
11408   operand *result, *right;
11409   int size, offset;
11410   unsigned long lit = 0L;
11411
11412   D (emitcode (";", "genAssign ");
11413     );
11414
11415   result = IC_RESULT (ic);
11416   right = IC_RIGHT (ic);
11417
11418   /* if they are the same */
11419   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11420     return;
11421
11422   aopOp (right, ic, FALSE, FALSE);
11423
11424   emitcode (";", "genAssign: resultIsFar = %s",
11425             isOperandInFarSpace (result) ?
11426             "TRUE" : "FALSE");
11427
11428   /* special case both in far space */
11429   if ((AOP_TYPE (right) == AOP_DPTR ||
11430        AOP_TYPE (right) == AOP_DPTR2) &&
11431   /* IS_TRUE_SYMOP(result)       && */
11432       isOperandInFarSpace (result))
11433     {
11434       genFarFarAssign (result, right, ic);
11435       return;
11436     }
11437
11438   aopOp (result, ic, TRUE, FALSE);
11439
11440   /* if they are the same registers */
11441   if (sameRegs (AOP (right), AOP (result)))
11442     goto release;
11443
11444   /* if the result is a bit */
11445   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
11446     {
11447       /* if the right size is a literal then
11448          we know what the value is */
11449       if (AOP_TYPE (right) == AOP_LIT)
11450         {
11451           if (((int) operandLitValue (right)))
11452             aopPut (AOP (result), one, 0);
11453           else
11454             aopPut (AOP (result), zero, 0);
11455           goto release;
11456         }
11457
11458       /* the right is also a bit variable */
11459       if (AOP_TYPE (right) == AOP_CRY)
11460         {
11461           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11462           aopPut (AOP (result), "c", 0);
11463           goto release;
11464         }
11465
11466       /* we need to or */
11467       toBoolean (right);
11468       aopPut (AOP (result), "a", 0);
11469       goto release;
11470     }
11471
11472   /* bit variables done */
11473   /* general case */
11474   size = AOP_SIZE (result);
11475   offset = 0;
11476   if (AOP_TYPE (right) == AOP_LIT)
11477     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11478
11479   if ((size > 1) &&
11480       (AOP_TYPE (result) != AOP_REG) &&
11481       (AOP_TYPE (right) == AOP_LIT) &&
11482       !IS_FLOAT (operandType (right)))
11483     {
11484       _startLazyDPSEvaluation ();
11485       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
11486         {
11487           aopPut (AOP (result),
11488                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11489                   offset);
11490           offset++;
11491           size--;
11492         }
11493       /* And now fill the rest with zeros. */
11494       if (size)
11495         {
11496           emitcode ("clr", "a");
11497         }
11498       while (size--)
11499         {
11500           aopPut (AOP (result), "a", offset++);
11501         }
11502       _endLazyDPSEvaluation ();
11503     }
11504   else
11505     {
11506       _startLazyDPSEvaluation ();
11507       while (size--)
11508         {
11509           aopPut (AOP (result),
11510                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11511                   offset);
11512           offset++;
11513         }
11514       _endLazyDPSEvaluation ();
11515     }
11516
11517 release:
11518   freeAsmop (right, NULL, ic, FALSE);
11519   freeAsmop (result, NULL, ic, TRUE);
11520 }
11521
11522 /*-----------------------------------------------------------------*/
11523 /* genJumpTab - generates code for jump table                      */
11524 /*-----------------------------------------------------------------*/
11525 static void
11526 genJumpTab (iCode * ic)
11527 {
11528   symbol *jtab;
11529   char *l;
11530
11531   D (emitcode (";", "genJumpTab ");
11532     );
11533
11534   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
11535   /* get the condition into accumulator */
11536   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE, NULL);
11537   MOVA (l);
11538   /* multiply by four! */
11539   emitcode ("add", "a,acc");
11540   emitcode ("add", "a,acc");
11541   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11542
11543   jtab = newiTempLabel (NULL);
11544   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
11545   emitcode ("jmp", "@a+dptr");
11546   emitcode ("", "!tlabeldef", jtab->key + 100);
11547   /* now generate the jump labels */
11548   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11549        jtab = setNextItem (IC_JTLABELS (ic)))
11550     emitcode ("ljmp", "!tlabel", jtab->key + 100);
11551
11552 }
11553
11554 /*-----------------------------------------------------------------*/
11555 /* genCast - gen code for casting                                  */
11556 /*-----------------------------------------------------------------*/
11557 static void
11558 genCast (iCode * ic)
11559 {
11560   operand *result = IC_RESULT (ic);
11561   sym_link *ctype = operandType (IC_LEFT (ic));
11562   sym_link *rtype = operandType (IC_RIGHT (ic));
11563   operand *right = IC_RIGHT (ic);
11564   int size, offset;
11565
11566   D (emitcode (";", "genCast "););
11567
11568   /* if they are equivalent then do nothing */
11569   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11570     return;
11571
11572   aopOp (right, ic, FALSE, AOP_IS_STR (result));
11573   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
11574
11575   /* if the result is a bit */
11576   if (IS_BITVAR (OP_SYMBOL (result)->type)
11577       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
11578     {
11579       /* if the right size is a literal then
11580          we know what the value is */
11581       if (AOP_TYPE (right) == AOP_LIT)
11582         {
11583           if (((int) operandLitValue (right)))
11584             aopPut (AOP (result), one, 0);
11585           else
11586             aopPut (AOP (result), zero, 0);
11587
11588           goto release;
11589         }
11590
11591       /* the right is also a bit variable */
11592       if (AOP_TYPE (right) == AOP_CRY)
11593         {
11594           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11595           aopPut (AOP (result), "c", 0);
11596           goto release;
11597         }
11598
11599       /* we need to or */
11600       toBoolean (right);
11601       aopPut (AOP (result), "a", 0);
11602       goto release;
11603     }
11604
11605   /* if they are the same size : or less */
11606   if (AOP_SIZE (result) <= AOP_SIZE (right))
11607     {
11608
11609       /* if they are in the same place */
11610       if (sameRegs (AOP (right), AOP (result)))
11611         goto release;
11612
11613       /* if they in different places then copy */
11614       size = AOP_SIZE (result);
11615       offset = 0;
11616       _startLazyDPSEvaluation ();
11617       while (size--)
11618         {
11619           aopPut (AOP (result),
11620                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11621                   offset);
11622           offset++;
11623         }
11624       _endLazyDPSEvaluation ();
11625       goto release;
11626     }
11627
11628
11629   /* if the result is of type pointer */
11630   if (IS_PTR (ctype))
11631     {
11632
11633       int p_type;
11634       sym_link *type = operandType (right);
11635
11636       /* pointer to generic pointer */
11637       if (IS_GENPTR (ctype))
11638         {
11639           if (IS_PTR (type))
11640             {
11641               p_type = DCL_TYPE (type);
11642             }
11643           else
11644             {
11645 #if OLD_CAST_BEHAVIOR
11646               /* KV: we are converting a non-pointer type to
11647                * a generic pointer. This (ifdef'd out) code
11648                * says that the resulting generic pointer
11649                * should have the same class as the storage
11650                * location of the non-pointer variable.
11651                *
11652                * For example, converting an int (which happens
11653                * to be stored in DATA space) to a pointer results
11654                * in a DATA generic pointer; if the original int
11655                * in XDATA space, so will be the resulting pointer.
11656                *
11657                * I don't like that behavior, and thus this change:
11658                * all such conversions will be forced to XDATA and
11659                * throw a warning. If you want some non-XDATA
11660                * type, or you want to suppress the warning, you
11661                * must go through an intermediate cast, like so:
11662                *
11663                * char _generic *gp = (char _xdata *)(intVar);
11664                */
11665               sym_link *etype = getSpec (type);
11666
11667               /* we have to go by the storage class */
11668               if (SPEC_OCLS (etype) != generic)
11669                 {
11670                   p_type = PTR_TYPE (SPEC_OCLS (etype));
11671                 }
11672               else
11673 #endif
11674                 {
11675                   /* Converting unknown class (i.e. register variable)
11676                    * to generic pointer. This is not good, but
11677                    * we'll make a guess (and throw a warning).
11678                    */
11679                   p_type = FPOINTER;
11680                   werror (W_INT_TO_GEN_PTR_CAST);
11681                 }
11682             }
11683
11684           /* the first two bytes are known */
11685           size = GPTRSIZE - 1;
11686           offset = 0;
11687           _startLazyDPSEvaluation ();
11688           while (size--)
11689             {
11690               aopPut (AOP (result),
11691                       aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11692                       offset);
11693               offset++;
11694             }
11695           _endLazyDPSEvaluation ();
11696
11697           /* the last byte depending on type */
11698             {
11699                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11700                 char gpValStr[10];
11701
11702                 if (gpVal == -1)
11703                 {
11704                     // pointerTypeToGPByte will have bitched.
11705                     exit(1);
11706                 }
11707
11708                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%d", gpVal);
11709                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1);
11710             }
11711           goto release;
11712         }
11713
11714       /* just copy the pointers */
11715       size = AOP_SIZE (result);
11716       offset = 0;
11717       _startLazyDPSEvaluation ();
11718       while (size--)
11719         {
11720           aopPut (AOP (result),
11721                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11722                   offset);
11723           offset++;
11724         }
11725       _endLazyDPSEvaluation ();
11726       goto release;
11727     }
11728
11729   /* so we now know that the size of destination is greater
11730      than the size of the source */
11731   /* we move to result for the size of source */
11732   size = AOP_SIZE (right);
11733   offset = 0;
11734   _startLazyDPSEvaluation ();
11735   while (size--)
11736     {
11737       aopPut (AOP (result),
11738               aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11739               offset);
11740       offset++;
11741     }
11742   _endLazyDPSEvaluation ();
11743
11744   /* now depending on the sign of the source && destination */
11745   size = AOP_SIZE (result) - AOP_SIZE (right);
11746   /* if unsigned or not an integral type */
11747   /* also, if the source is a bit, we don't need to sign extend, because
11748    * it can't possibly have set the sign bit.
11749    */
11750   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
11751     {
11752       while (size--)
11753         {
11754           aopPut (AOP (result), zero, offset++);
11755         }
11756     }
11757   else
11758     {
11759       /* we need to extend the sign :{ */
11760       MOVA (aopGet (AOP (right), AOP_SIZE (right) - 1,
11761                         FALSE, FALSE, NULL));
11762       emitcode ("rlc", "a");
11763       emitcode ("subb", "a,acc");
11764       while (size--)
11765         aopPut (AOP (result), "a", offset++);
11766     }
11767
11768   /* we are done hurray !!!! */
11769
11770 release:
11771   freeAsmop (right, NULL, ic, TRUE);
11772   freeAsmop (result, NULL, ic, TRUE);
11773
11774 }
11775
11776 /*-----------------------------------------------------------------*/
11777 /* genDjnz - generate decrement & jump if not zero instrucion      */
11778 /*-----------------------------------------------------------------*/
11779 static int
11780 genDjnz (iCode * ic, iCode * ifx)
11781 {
11782   symbol *lbl, *lbl1;
11783   if (!ifx)
11784     return 0;
11785
11786   /* if the if condition has a false label
11787      then we cannot save */
11788   if (IC_FALSE (ifx))
11789     return 0;
11790
11791   /* if the minus is not of the form
11792      a = a - 1 */
11793   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11794       !IS_OP_LITERAL (IC_RIGHT (ic)))
11795     return 0;
11796
11797   if (operandLitValue (IC_RIGHT (ic)) != 1)
11798     return 0;
11799
11800   /* if the size of this greater than one then no
11801      saving */
11802   if (getSize (operandType (IC_RESULT (ic))) > 1)
11803     return 0;
11804
11805   /* otherwise we can save BIG */
11806   D(emitcode(";", "genDjnz"););
11807
11808   lbl = newiTempLabel (NULL);
11809   lbl1 = newiTempLabel (NULL);
11810
11811   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11812
11813   if (AOP_NEEDSACC(IC_RESULT(ic)))
11814   {
11815       /* If the result is accessed indirectly via
11816        * the accumulator, we must explicitly write
11817        * it back after the decrement.
11818        */
11819       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE, NULL);
11820
11821       if (strcmp(rByte, "a"))
11822       {
11823            /* Something is hopelessly wrong */
11824            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11825                    __FILE__, __LINE__);
11826            /* We can just give up; the generated code will be inefficient,
11827             * but what the hey.
11828             */
11829            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11830            return 0;
11831       }
11832       emitcode ("dec", "%s", rByte);
11833       aopPut(AOP(IC_RESULT(ic)), rByte, 0);
11834       emitcode ("jnz", "!tlabel", lbl->key + 100);
11835   }
11836   else if (IS_AOP_PREG (IC_RESULT (ic)))
11837     {
11838       emitcode ("dec", "%s",
11839                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11840       emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11841       emitcode ("jnz", "!tlabel", lbl->key + 100);
11842     }
11843   else
11844     {
11845       emitcode ("djnz", "%s,!tlabel", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, TRUE, NULL),
11846                 lbl->key + 100);
11847     }
11848   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
11849   emitcode ("", "!tlabeldef", lbl->key + 100);
11850   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
11851   emitcode ("", "!tlabeldef", lbl1->key + 100);
11852
11853   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11854   ifx->generated = 1;
11855   return 1;
11856 }
11857
11858 /*-----------------------------------------------------------------*/
11859 /* genReceive - generate code for a receive iCode                  */
11860 /*-----------------------------------------------------------------*/
11861 static void
11862 genReceive (iCode * ic)
11863 {
11864     int size = getSize (operandType (IC_RESULT (ic)));
11865     int offset = 0;
11866     int rb1off ;
11867
11868     D (emitcode (";", "genReceive "););
11869
11870     if (ic->argreg == 1)
11871     {
11872         /* first parameter */
11873         if (AOP_IS_STR(IC_RESULT(ic)))
11874         {
11875             /* Nothing to do: it's already in the proper place. */
11876             return;
11877         }
11878         else
11879         {
11880             bool useDp2;
11881
11882             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
11883                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11884                  IS_TRUE_SYMOP (IC_RESULT (ic)));
11885
11886             _G.accInUse++;
11887             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
11888             _G.accInUse--;
11889
11890             /* Sanity checking... */
11891             if (AOP_USESDPTR(IC_RESULT(ic)))
11892             {
11893                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11894                         "genReceive got unexpected DPTR.");
11895             }
11896             assignResultValue (IC_RESULT (ic));
11897         }
11898     }
11899     else
11900     {
11901         /* second receive onwards */
11902         /* this gets a little tricky since unused recevies will be
11903          eliminated, we have saved the reg in the type field . and
11904          we use that to figure out which register to use */
11905         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11906         rb1off = ic->argreg;
11907         while (size--)
11908         {
11909             aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++);
11910         }
11911     }
11912     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11913 }
11914
11915 /*-----------------------------------------------------------------*/
11916 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
11917 /*-----------------------------------------------------------------*/
11918 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
11919 {
11920     operand *from , *to , *count;
11921     symbol *lbl;
11922     bitVect *rsave;
11923     int i;
11924
11925     /* we know it has to be 3 parameters */
11926     assert (nparms == 3);
11927
11928     rsave = newBitVect(16);
11929     /* save DPTR if it needs to be saved */
11930     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11931             if (bitVectBitValue(ic->rMask,i))
11932                     rsave = bitVectSetBit(rsave,i);
11933     }
11934     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11935                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11936     savermask(rsave);
11937
11938     to = parms[0];
11939     from = parms[1];
11940     count = parms[2];
11941
11942     aopOp (from, ic->next, FALSE, FALSE);
11943
11944     /* get from into DPTR1 */
11945     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11946     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11947     if (options.model == MODEL_FLAT24) {
11948         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11949     }
11950
11951     freeAsmop (from, NULL, ic, FALSE);
11952     aopOp (to, ic, FALSE, FALSE);
11953     /* get "to" into DPTR */
11954     /* if the operand is already in dptr
11955        then we do nothing else we move the value to dptr */
11956     if (AOP_TYPE (to) != AOP_STR) {
11957         /* if already in DPTR then we need to push */
11958         if (AOP_TYPE(to) == AOP_DPTR) {
11959             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11960             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11961             if (options.model == MODEL_FLAT24)
11962                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11963             emitcode ("pop", "dph");
11964             emitcode ("pop", "dpl");
11965         } else {
11966             _startLazyDPSEvaluation ();
11967             /* if this is remateriazable */
11968             if (AOP_TYPE (to) == AOP_IMMD) {
11969                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11970             } else {                    /* we need to get it byte by byte */
11971                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11972                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11973                 if (options.model == MODEL_FLAT24) {
11974                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11975                 }
11976             }
11977             _endLazyDPSEvaluation ();
11978         }
11979     }
11980     freeAsmop (to, NULL, ic, FALSE);
11981     _G.dptrInUse = _G.dptr1InUse = 1;
11982     aopOp (count, ic->next->next, FALSE,FALSE);
11983     lbl =newiTempLabel(NULL);
11984
11985     /* now for the actual copy */
11986     if (AOP_TYPE(count) == AOP_LIT &&
11987         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11988         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11989         if (fromc) {
11990             emitcode ("lcall","__bi_memcpyc2x_s");
11991         } else {
11992             emitcode ("lcall","__bi_memcpyx2x_s");
11993         }
11994         freeAsmop (count, NULL, ic, FALSE);
11995     } else {
11996         symbol *lbl1 = newiTempLabel(NULL);
11997
11998         emitcode (";"," Auto increment but no djnz");
11999         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12000         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12001         freeAsmop (count, NULL, ic, FALSE);
12002         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12003         emitcode ("","!tlabeldef",lbl->key+100);
12004         if (fromc) {
12005             emitcode ("clr","a");
12006             emitcode ("movc", "a,@a+dptr");
12007         } else
12008             emitcode ("movx", "a,@dptr");
12009         emitcode ("movx", "@dptr,a");
12010         emitcode ("inc", "dptr");
12011         emitcode ("inc", "dptr");
12012         emitcode ("mov","a,b");
12013         emitcode ("orl","a,_ap");
12014         emitcode ("jz","!tlabel",lbl1->key+100);
12015         emitcode ("mov","a,_ap");
12016         emitcode ("add","a,#!constbyte",0xFF);
12017         emitcode ("mov","_ap,a");
12018         emitcode ("mov","a,b");
12019         emitcode ("addc","a,#!constbyte",0xFF);
12020         emitcode ("mov","b,a");
12021         emitcode ("sjmp","!tlabel",lbl->key+100);
12022         emitcode ("","!tlabeldef",lbl1->key+100);
12023     }
12024     emitcode ("mov", "dps,#0");
12025     _G.dptrInUse = _G.dptr1InUse = 0;
12026     unsavermask(rsave);
12027
12028 }
12029
12030 /*-----------------------------------------------------------------*/
12031 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12032 /*-----------------------------------------------------------------*/
12033 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12034 {
12035     operand *from , *to , *count;
12036     symbol *lbl,*lbl2;
12037     bitVect *rsave;
12038     int i;
12039
12040     /* we know it has to be 3 parameters */
12041     assert (nparms == 3);
12042
12043     rsave = newBitVect(16);
12044     /* save DPTR if it needs to be saved */
12045     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12046             if (bitVectBitValue(ic->rMask,i))
12047                     rsave = bitVectSetBit(rsave,i);
12048     }
12049     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12050                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12051     savermask(rsave);
12052
12053     to = parms[0];
12054     from = parms[1];
12055     count = parms[2];
12056
12057     aopOp (from, ic->next, FALSE, FALSE);
12058
12059     /* get from into DPTR1 */
12060     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12061     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12062     if (options.model == MODEL_FLAT24) {
12063         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12064     }
12065
12066     freeAsmop (from, NULL, ic, FALSE);
12067     aopOp (to, ic, FALSE, FALSE);
12068     /* get "to" into DPTR */
12069     /* if the operand is already in dptr
12070        then we do nothing else we move the value to dptr */
12071     if (AOP_TYPE (to) != AOP_STR) {
12072         /* if already in DPTR then we need to push */
12073         if (AOP_TYPE(to) == AOP_DPTR) {
12074             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12075             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12076             if (options.model == MODEL_FLAT24)
12077                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12078             emitcode ("pop", "dph");
12079             emitcode ("pop", "dpl");
12080         } else {
12081             _startLazyDPSEvaluation ();
12082             /* if this is remateriazable */
12083             if (AOP_TYPE (to) == AOP_IMMD) {
12084                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12085             } else {                    /* we need to get it byte by byte */
12086                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12087                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12088                 if (options.model == MODEL_FLAT24) {
12089                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12090                 }
12091             }
12092             _endLazyDPSEvaluation ();
12093         }
12094     }
12095     freeAsmop (to, NULL, ic, FALSE);
12096     _G.dptrInUse = _G.dptr1InUse = 1;
12097     aopOp (count, ic->next->next, FALSE,FALSE);
12098     lbl =newiTempLabel(NULL);
12099     lbl2 =newiTempLabel(NULL);
12100
12101     /* now for the actual compare */
12102     if (AOP_TYPE(count) == AOP_LIT &&
12103         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12104         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12105         if (fromc)
12106             emitcode("lcall","__bi_memcmpc2x_s");
12107         else
12108             emitcode("lcall","__bi_memcmpx2x_s");
12109         freeAsmop (count, NULL, ic, FALSE);
12110         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12111         aopPut(AOP(IC_RESULT(ic)),"a",0);
12112         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12113     } else {
12114         symbol *lbl1 = newiTempLabel(NULL);
12115
12116         emitcode("push","ar0");
12117         emitcode (";"," Auto increment but no djnz");
12118         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12119         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12120         freeAsmop (count, NULL, ic, FALSE);
12121         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12122         emitcode ("","!tlabeldef",lbl->key+100);
12123         if (fromc) {
12124             emitcode ("clr","a");
12125             emitcode ("movc", "a,@a+dptr");
12126         } else
12127             emitcode ("movx", "a,@dptr");
12128         emitcode ("mov","r0,a");
12129         emitcode ("movx", "a,@dptr");
12130         emitcode ("clr","c");
12131         emitcode ("subb","a,r0");
12132         emitcode ("jnz","!tlabel",lbl2->key+100);
12133         emitcode ("inc", "dptr");
12134         emitcode ("inc", "dptr");
12135         emitcode ("mov","a,b");
12136         emitcode ("orl","a,_ap");
12137         emitcode ("jz","!tlabel",lbl1->key+100);
12138         emitcode ("mov","a,_ap");
12139         emitcode ("add","a,#!constbyte",0xFF);
12140         emitcode ("mov","_ap,a");
12141         emitcode ("mov","a,b");
12142         emitcode ("addc","a,#!constbyte",0xFF);
12143         emitcode ("mov","b,a");
12144         emitcode ("sjmp","!tlabel",lbl->key+100);
12145         emitcode ("","!tlabeldef",lbl1->key+100);
12146         emitcode ("clr","a");
12147         emitcode ("","!tlabeldef",lbl2->key+100);
12148         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12149         aopPut(AOP(IC_RESULT(ic)),"a",0);
12150         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12151         emitcode("pop","ar0");
12152         emitcode ("mov", "dps,#0");
12153     }
12154     _G.dptrInUse = _G.dptr1InUse = 0;
12155     unsavermask(rsave);
12156
12157 }
12158
12159 /*-----------------------------------------------------------------*/
12160 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12161 /* port, first parameter output area second parameter pointer to   */
12162 /* port third parameter count                                      */
12163 /*-----------------------------------------------------------------*/
12164 static void genInp( iCode *ic, int nparms, operand **parms)
12165 {
12166     operand *from , *to , *count;
12167     symbol *lbl;
12168     bitVect *rsave;
12169     int i;
12170
12171     /* we know it has to be 3 parameters */
12172     assert (nparms == 3);
12173
12174     rsave = newBitVect(16);
12175     /* save DPTR if it needs to be saved */
12176     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12177             if (bitVectBitValue(ic->rMask,i))
12178                     rsave = bitVectSetBit(rsave,i);
12179     }
12180     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12181                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12182     savermask(rsave);
12183
12184     to = parms[0];
12185     from = parms[1];
12186     count = parms[2];
12187
12188     aopOp (from, ic->next, FALSE, FALSE);
12189
12190     /* get from into DPTR1 */
12191     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12192     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12193     if (options.model == MODEL_FLAT24) {
12194         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12195     }
12196
12197     freeAsmop (from, NULL, ic, FALSE);
12198     aopOp (to, ic, FALSE, FALSE);
12199     /* get "to" into DPTR */
12200     /* if the operand is already in dptr
12201        then we do nothing else we move the value to dptr */
12202     if (AOP_TYPE (to) != AOP_STR) {
12203         /* if already in DPTR then we need to push */
12204         if (AOP_TYPE(to) == AOP_DPTR) {
12205             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12206             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12207             if (options.model == MODEL_FLAT24)
12208                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12209             emitcode ("pop", "dph");
12210             emitcode ("pop", "dpl");
12211         } else {
12212             _startLazyDPSEvaluation ();
12213             /* if this is remateriazable */
12214             if (AOP_TYPE (to) == AOP_IMMD) {
12215                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12216             } else {                    /* we need to get it byte by byte */
12217                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12218                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12219                 if (options.model == MODEL_FLAT24) {
12220                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12221                 }
12222             }
12223             _endLazyDPSEvaluation ();
12224         }
12225     }
12226     freeAsmop (to, NULL, ic, FALSE);
12227
12228     _G.dptrInUse = _G.dptr1InUse = 1;
12229     aopOp (count, ic->next->next, FALSE,FALSE);
12230     lbl =newiTempLabel(NULL);
12231
12232     /* now for the actual copy */
12233     if (AOP_TYPE(count) == AOP_LIT &&
12234         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12235         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12236         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12237         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12238         freeAsmop (count, NULL, ic, FALSE);
12239         emitcode ("","!tlabeldef",lbl->key+100);
12240         emitcode ("movx", "a,@dptr");   /* read data from port */
12241         emitcode ("dec","dps");         /* switch to DPTR */
12242         emitcode ("movx", "@dptr,a");   /* save into location */
12243         emitcode ("inc", "dptr");       /* point to next area */
12244         emitcode ("inc","dps");         /* switch to DPTR2 */
12245         emitcode ("djnz","b,!tlabel",lbl->key+100);
12246     } else {
12247         symbol *lbl1 = newiTempLabel(NULL);
12248
12249         emitcode (";"," Auto increment but no djnz");
12250         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12251         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12252         freeAsmop (count, NULL, ic, FALSE);
12253         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12254         emitcode ("","!tlabeldef",lbl->key+100);
12255         emitcode ("movx", "a,@dptr");
12256         emitcode ("dec","dps");         /* switch to DPTR */
12257         emitcode ("movx", "@dptr,a");
12258         emitcode ("inc", "dptr");
12259         emitcode ("inc","dps");         /* switch to DPTR2 */
12260 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12261 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12262         emitcode ("mov","a,b");
12263         emitcode ("orl","a,_ap");
12264         emitcode ("jz","!tlabel",lbl1->key+100);
12265         emitcode ("mov","a,_ap");
12266         emitcode ("add","a,#!constbyte",0xFF);
12267         emitcode ("mov","_ap,a");
12268         emitcode ("mov","a,b");
12269         emitcode ("addc","a,#!constbyte",0xFF);
12270         emitcode ("mov","b,a");
12271         emitcode ("sjmp","!tlabel",lbl->key+100);
12272         emitcode ("","!tlabeldef",lbl1->key+100);
12273     }
12274     emitcode ("mov", "dps,#0");
12275     _G.dptrInUse = _G.dptr1InUse = 0;
12276     unsavermask(rsave);
12277
12278 }
12279
12280 /*-----------------------------------------------------------------*/
12281 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12282 /* port, first parameter output area second parameter pointer to   */
12283 /* port third parameter count                                      */
12284 /*-----------------------------------------------------------------*/
12285 static void genOutp( iCode *ic, int nparms, operand **parms)
12286 {
12287     operand *from , *to , *count;
12288     symbol *lbl;
12289     bitVect *rsave;
12290     int i;
12291
12292     /* we know it has to be 3 parameters */
12293     assert (nparms == 3);
12294
12295     rsave = newBitVect(16);
12296     /* save DPTR if it needs to be saved */
12297     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12298             if (bitVectBitValue(ic->rMask,i))
12299                     rsave = bitVectSetBit(rsave,i);
12300     }
12301     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12302                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12303     savermask(rsave);
12304
12305     to = parms[0];
12306     from = parms[1];
12307     count = parms[2];
12308
12309     aopOp (from, ic->next, FALSE, FALSE);
12310
12311     /* get from into DPTR1 */
12312     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12313     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12314     if (options.model == MODEL_FLAT24) {
12315         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12316     }
12317
12318     freeAsmop (from, NULL, ic, FALSE);
12319     aopOp (to, ic, FALSE, FALSE);
12320     /* get "to" into DPTR */
12321     /* if the operand is already in dptr
12322        then we do nothing else we move the value to dptr */
12323     if (AOP_TYPE (to) != AOP_STR) {
12324         /* if already in DPTR then we need to push */
12325         if (AOP_TYPE(to) == AOP_DPTR) {
12326             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12327             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12328             if (options.model == MODEL_FLAT24)
12329                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12330             emitcode ("pop", "dph");
12331             emitcode ("pop", "dpl");
12332         } else {
12333             _startLazyDPSEvaluation ();
12334             /* if this is remateriazable */
12335             if (AOP_TYPE (to) == AOP_IMMD) {
12336                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12337             } else {                    /* we need to get it byte by byte */
12338                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12339                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12340                 if (options.model == MODEL_FLAT24) {
12341                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12342                 }
12343             }
12344             _endLazyDPSEvaluation ();
12345         }
12346     }
12347     freeAsmop (to, NULL, ic, FALSE);
12348
12349     _G.dptrInUse = _G.dptr1InUse = 1;
12350     aopOp (count, ic->next->next, FALSE,FALSE);
12351     lbl =newiTempLabel(NULL);
12352
12353     /* now for the actual copy */
12354     if (AOP_TYPE(count) == AOP_LIT &&
12355         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12356         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12357         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12358         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12359         emitcode ("","!tlabeldef",lbl->key+100);
12360         emitcode ("movx", "a,@dptr");   /* read data from port */
12361         emitcode ("inc","dps");         /* switch to DPTR2 */
12362         emitcode ("movx", "@dptr,a");   /* save into location */
12363         emitcode ("inc", "dptr");       /* point to next area */
12364         emitcode ("dec","dps");         /* switch to DPTR */
12365         emitcode ("djnz","b,!tlabel",lbl->key+100);
12366         freeAsmop (count, NULL, ic, FALSE);
12367     } else {
12368         symbol *lbl1 = newiTempLabel(NULL);
12369
12370         emitcode (";"," Auto increment but no djnz");
12371         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12372         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12373         freeAsmop (count, NULL, ic, FALSE);
12374         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12375         emitcode ("","!tlabeldef",lbl->key+100);
12376         emitcode ("movx", "a,@dptr");
12377         emitcode ("inc", "dptr");
12378         emitcode ("inc","dps");         /* switch to DPTR2 */
12379         emitcode ("movx", "@dptr,a");
12380         emitcode ("dec","dps");         /* switch to DPTR */
12381         emitcode ("mov","a,b");
12382         emitcode ("orl","a,_ap");
12383         emitcode ("jz","!tlabel",lbl1->key+100);
12384         emitcode ("mov","a,_ap");
12385         emitcode ("add","a,#!constbyte",0xFF);
12386         emitcode ("mov","_ap,a");
12387         emitcode ("mov","a,b");
12388         emitcode ("addc","a,#!constbyte",0xFF);
12389         emitcode ("mov","b,a");
12390         emitcode ("sjmp","!tlabel",lbl->key+100);
12391         emitcode ("","!tlabeldef",lbl1->key+100);
12392     }
12393     emitcode ("mov", "dps,#0");
12394     _G.dptrInUse = _G.dptr1InUse = 0;
12395     unsavermask(rsave);
12396
12397 }
12398
12399 /*-----------------------------------------------------------------*/
12400 /* genSwapW - swap lower & high order bytes                        */
12401 /*-----------------------------------------------------------------*/
12402 static void genSwapW(iCode *ic, int nparms, operand **parms)
12403 {
12404     operand *dest;
12405     operand *src;
12406     assert (nparms==1);
12407
12408     src = parms[0];
12409     dest=IC_RESULT(ic);
12410
12411     assert(getSize(operandType(src))==2);
12412
12413     aopOp (src, ic, FALSE, FALSE);
12414     emitcode ("mov","a,%s",aopGet(AOP(src),0,FALSE,FALSE,NULL));
12415     _G.accInUse++;
12416     MOVB(aopGet(AOP(src),1,FALSE,FALSE,"b"));
12417     _G.accInUse--;
12418     freeAsmop (src, NULL, ic, FALSE);
12419
12420     aopOp (dest,ic, FALSE, FALSE);
12421     aopPut(AOP(dest),"b",0);
12422     aopPut(AOP(dest),"a",1);
12423     freeAsmop (dest, NULL, ic, FALSE);
12424 }
12425
12426 /*-----------------------------------------------------------------*/
12427 /* genMemsetX - gencode for memSetX data                           */
12428 /*-----------------------------------------------------------------*/
12429 static void genMemsetX(iCode *ic, int nparms, operand **parms)
12430 {
12431     operand *to , *val , *count;
12432     symbol *lbl;
12433     char *l;
12434     int i;
12435     bitVect *rsave;
12436
12437     /* we know it has to be 3 parameters */
12438     assert (nparms == 3);
12439
12440     to = parms[0];
12441     val = parms[1];
12442     count = parms[2];
12443
12444     /* save DPTR if it needs to be saved */
12445     rsave = newBitVect(16);
12446     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12447             if (bitVectBitValue(ic->rMask,i))
12448                     rsave = bitVectSetBit(rsave,i);
12449     }
12450     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12451                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12452     savermask(rsave);
12453
12454     aopOp (to, ic, FALSE, FALSE);
12455     /* get "to" into DPTR */
12456     /* if the operand is already in dptr
12457        then we do nothing else we move the value to dptr */
12458     if (AOP_TYPE (to) != AOP_STR) {
12459         /* if already in DPTR then we need to push */
12460         if (AOP_TYPE(to) == AOP_DPTR) {
12461             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12462             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12463             if (options.model == MODEL_FLAT24)
12464                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12465             emitcode ("pop", "dph");
12466             emitcode ("pop", "dpl");
12467         } else {
12468             _startLazyDPSEvaluation ();
12469             /* if this is remateriazable */
12470             if (AOP_TYPE (to) == AOP_IMMD) {
12471                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12472             } else {                    /* we need to get it byte by byte */
12473                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12474                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12475                 if (options.model == MODEL_FLAT24) {
12476                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12477                 }
12478             }
12479             _endLazyDPSEvaluation ();
12480         }
12481     }
12482     freeAsmop (to, NULL, ic, FALSE);
12483
12484     aopOp (val, ic->next->next, FALSE,FALSE);
12485     aopOp (count, ic->next->next, FALSE,FALSE);
12486     lbl =newiTempLabel(NULL);
12487     /* now for the actual copy */
12488     if (AOP_TYPE(count) == AOP_LIT &&
12489         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12490         l = aopGet(AOP (val), 0, FALSE, FALSE, NULL);
12491         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12492         MOVA(l);
12493         emitcode ("","!tlabeldef",lbl->key+100);
12494         emitcode ("movx", "@dptr,a");
12495         emitcode ("inc", "dptr");
12496         emitcode ("djnz","b,!tlabel",lbl->key+100);
12497     } else {
12498         symbol *lbl1 = newiTempLabel(NULL);
12499
12500         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12501         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12502         emitcode ("","!tlabeldef",lbl->key+100);
12503         MOVA (aopGet(AOP (val), 0, FALSE, FALSE, NULL));
12504         emitcode ("movx", "@dptr,a");
12505         emitcode ("inc", "dptr");
12506         emitcode ("mov","a,b");
12507         emitcode ("orl","a,_ap");
12508         emitcode ("jz","!tlabel",lbl1->key+100);
12509         emitcode ("mov","a,_ap");
12510         emitcode ("add","a,#!constbyte",0xFF);
12511         emitcode ("mov","_ap,a");
12512         emitcode ("mov","a,b");
12513         emitcode ("addc","a,#!constbyte",0xFF);
12514         emitcode ("mov","b,a");
12515         emitcode ("sjmp","!tlabel",lbl->key+100);
12516         emitcode ("","!tlabeldef",lbl1->key+100);
12517     }
12518     freeAsmop (count, NULL, ic, FALSE);
12519     unsavermask(rsave);
12520 }
12521
12522 /*-----------------------------------------------------------------*/
12523 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
12524 /*-----------------------------------------------------------------*/
12525 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
12526 {
12527         bitVect *rsave ;
12528         operand *pnum, *result;
12529         int i;
12530
12531         assert (nparms==1);
12532         /* save registers that need to be saved */
12533         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12534                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12535
12536         pnum = parms[0];
12537         aopOp (pnum, ic, FALSE, FALSE);
12538         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
12539         freeAsmop (pnum, NULL, ic, FALSE);
12540         emitcode ("lcall","NatLib_LoadPrimitive");
12541         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
12542         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
12543             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
12544                 for (i = (size-1) ; i >= 0 ; i-- ) {
12545                         emitcode ("push","a%s",javaRet[i]);
12546                 }
12547                 for (i=0; i < size ; i++ ) {
12548                         emitcode ("pop","a%s",
12549                                   aopGet(AOP(result),i,FALSE,FALSE,DP2_RESULT_REG));
12550                 }
12551         } else {
12552                 for (i = 0 ; i < size ; i++ ) {
12553                         aopPut(AOP(result),javaRet[i],i);
12554                 }
12555         }
12556         freeAsmop (result, NULL, ic, FALSE);
12557         unsavermask(rsave);
12558 }
12559
12560 /*-----------------------------------------------------------------*/
12561 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
12562 /*-----------------------------------------------------------------*/
12563 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
12564 {
12565         bitVect *rsave ;
12566         operand *pnum, *result;
12567         int size = 3;
12568         int i;
12569
12570         assert (nparms==1);
12571         /* save registers that need to be saved */
12572         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12573                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12574
12575         pnum = parms[0];
12576         aopOp (pnum, ic, FALSE, FALSE);
12577         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
12578         freeAsmop (pnum, NULL, ic, FALSE);
12579         emitcode ("lcall","NatLib_LoadPointer");
12580         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
12581         if (AOP_TYPE(result)!=AOP_STR) {
12582                 for (i = 0 ; i < size ; i++ ) {
12583                         aopPut(AOP(result),fReturn[i],i);
12584                 }
12585         }
12586         freeAsmop (result, NULL, ic, FALSE);
12587         unsavermask(rsave);
12588 }
12589
12590 /*-----------------------------------------------------------------*/
12591 /* genNatLibInstallStateBlock -                                    */
12592 /*-----------------------------------------------------------------*/
12593 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
12594                                        operand **parms, const char *name)
12595 {
12596         bitVect *rsave ;
12597         operand *psb, *handle;
12598         assert (nparms==2);
12599
12600         /* save registers that need to be saved */
12601         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12602                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12603         psb = parms[0];
12604         handle = parms[1];
12605
12606         /* put pointer to state block into DPTR1 */
12607         aopOp (psb, ic, FALSE, FALSE);
12608         if (AOP_TYPE (psb) == AOP_IMMD) {
12609                 emitcode ("mov","dps,#1");
12610                 emitcode ("mov", "dptr,%s",
12611                           aopGet (AOP (psb), 0, TRUE, FALSE, DP2_RESULT_REG));
12612                 emitcode ("mov","dps,#0");
12613         } else {
12614                 emitcode ("mov","dpl1,%s",aopGet(AOP(psb),0,FALSE,FALSE,DP2_RESULT_REG));
12615                 emitcode ("mov","dph1,%s",aopGet(AOP(psb),1,FALSE,FALSE,DP2_RESULT_REG));
12616                 emitcode ("mov","dpx1,%s",aopGet(AOP(psb),2,FALSE,FALSE,DP2_RESULT_REG));
12617         }
12618         freeAsmop (psb, NULL, ic, FALSE);
12619
12620         /* put libraryID into DPTR */
12621         emitcode ("mov","dptr,#LibraryID");
12622
12623         /* put handle into r3:r2 */
12624         aopOp (handle, ic, FALSE, FALSE);
12625         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12626                 emitcode ("push","%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12627                 emitcode ("push","%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12628                 emitcode ("pop","ar3");
12629                 emitcode ("pop","ar2");
12630         } else {
12631                 emitcode ("mov","r2,%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12632                 emitcode ("mov","r3,%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12633         }
12634         freeAsmop (psb, NULL, ic, FALSE);
12635
12636         /* make the call */
12637         emitcode ("lcall","NatLib_Install%sStateBlock",name);
12638
12639         /* put return value into place*/
12640         _G.accInUse++;
12641         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
12642         _G.accInUse--;
12643         aopPut(AOP(IC_RESULT(ic)),"a",0);
12644         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12645         unsavermask(rsave);
12646 }
12647
12648 /*-----------------------------------------------------------------*/
12649 /* genNatLibRemoveStateBlock -                                     */
12650 /*-----------------------------------------------------------------*/
12651 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
12652 {
12653         bitVect *rsave ;
12654
12655         assert(nparms==0);
12656
12657         /* save registers that need to be saved */
12658         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12659                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12660
12661         /* put libraryID into DPTR */
12662         emitcode ("mov","dptr,#LibraryID");
12663         /* make the call */
12664         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12665         unsavermask(rsave);
12666 }
12667
12668 /*-----------------------------------------------------------------*/
12669 /* genNatLibGetStateBlock -                                        */
12670 /*-----------------------------------------------------------------*/
12671 static void genNatLibGetStateBlock(iCode *ic,int nparms,
12672                                    operand **parms,const char *name)
12673 {
12674         bitVect *rsave ;
12675         symbol *lbl = newiTempLabel(NULL);
12676
12677         assert(nparms==0);
12678         /* save registers that need to be saved */
12679         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12680                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12681
12682         /* put libraryID into DPTR */
12683         emitcode ("mov","dptr,#LibraryID");
12684         /* make the call */
12685         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12686         emitcode ("jnz","!tlabel",lbl->key+100);
12687
12688         /* put return value into place */
12689         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12690         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12691                 emitcode ("push","ar3");
12692                 emitcode ("push","ar2");
12693                 emitcode ("pop","%s",
12694                           aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12695                 emitcode ("pop","%s",
12696                           aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12697         } else {
12698                 aopPut(AOP(IC_RESULT(ic)),"r2",0);
12699                 aopPut(AOP(IC_RESULT(ic)),"r3",1);
12700         }
12701         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12702         emitcode ("","!tlabeldef",lbl->key+100);
12703         unsavermask(rsave);
12704 }
12705
12706 /*-----------------------------------------------------------------*/
12707 /* genMMMalloc -                                                   */
12708 /*-----------------------------------------------------------------*/
12709 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
12710                          int size, const char *name)
12711 {
12712         bitVect *rsave ;
12713         operand *bsize;
12714         symbol *rsym;
12715         symbol *lbl = newiTempLabel(NULL);
12716
12717         assert (nparms == 1);
12718         /* save registers that need to be saved */
12719         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12720                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12721
12722         bsize=parms[0];
12723         aopOp (bsize,ic,FALSE,FALSE);
12724
12725         /* put the size in R4-R2 */
12726         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
12727                 emitcode("push","%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12728                 emitcode("push","%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12729                 if (size==3) {
12730                         emitcode("push","%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12731                         emitcode("pop","ar4");
12732                 }
12733                 emitcode("pop","ar3");
12734                 emitcode("pop","ar2");
12735         } else {
12736                 emitcode ("mov","r2,%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12737                 emitcode ("mov","r3,%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12738                 if (size==3) {
12739                         emitcode("mov","r4,%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12740                 }
12741         }
12742         freeAsmop (bsize, NULL, ic, FALSE);
12743
12744         /* make the call */
12745         emitcode ("lcall","MM_%s",name);
12746         emitcode ("jz","!tlabel",lbl->key+100);
12747         emitcode ("mov","r2,#!constbyte",0xff);
12748         emitcode ("mov","r3,#!constbyte",0xff);
12749         emitcode ("","!tlabeldef",lbl->key+100);
12750         /* we don't care about the pointer : we just save the handle */
12751         rsym = OP_SYMBOL(IC_RESULT(ic));
12752         if (rsym->liveFrom != rsym->liveTo) {
12753                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12754                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12755                         emitcode ("push","ar3");
12756                         emitcode ("push","ar2");
12757                         emitcode ("pop","%s",
12758                                   aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12759                         emitcode ("pop","%s",
12760                                   aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12761                 } else {
12762                         aopPut(AOP(IC_RESULT(ic)),"r2",0);
12763                         aopPut(AOP(IC_RESULT(ic)),"r3",1);
12764                 }
12765                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12766         }
12767         unsavermask(rsave);
12768 }
12769
12770 /*-----------------------------------------------------------------*/
12771 /* genMMDeref -                                                    */
12772 /*-----------------------------------------------------------------*/
12773 static void genMMDeref (iCode *ic,int nparms, operand **parms)
12774 {
12775         bitVect *rsave ;
12776         operand *handle;
12777
12778         assert (nparms == 1);
12779         /* save registers that need to be saved */
12780         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12781                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12782
12783         handle=parms[0];
12784         aopOp (handle,ic,FALSE,FALSE);
12785
12786         /* put the size in R4-R2 */
12787         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12788                 emitcode("push","%s",
12789                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12790                 emitcode("push","%s",
12791                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12792                 emitcode("pop","ar3");
12793                 emitcode("pop","ar2");
12794         } else {
12795                 emitcode ("mov","r2,%s",
12796                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12797                 emitcode ("mov","r3,%s",
12798                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12799         }
12800         freeAsmop (handle, NULL, ic, FALSE);
12801
12802         /* make the call */
12803         emitcode ("lcall","MM_Deref");
12804
12805         {
12806                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12807                 if (rsym->liveFrom != rsym->liveTo) {
12808                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12809                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
12810                             _startLazyDPSEvaluation ();
12811
12812                                 aopPut(AOP(IC_RESULT(ic)),"dpl",0);
12813                                 aopPut(AOP(IC_RESULT(ic)),"dph",1);
12814                                 aopPut(AOP(IC_RESULT(ic)),"dpx",2);
12815
12816                             _endLazyDPSEvaluation ();
12817
12818                         }
12819                 }
12820         }
12821         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12822         unsavermask(rsave);
12823 }
12824
12825 /*-----------------------------------------------------------------*/
12826 /* genMMUnrestrictedPersist -                                      */
12827 /*-----------------------------------------------------------------*/
12828 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
12829 {
12830         bitVect *rsave ;
12831         operand *handle;
12832
12833         assert (nparms == 1);
12834         /* save registers that need to be saved */
12835         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12836                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12837
12838         handle=parms[0];
12839         aopOp (handle,ic,FALSE,FALSE);
12840
12841         /* put the size in R3-R2 */
12842         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12843                 emitcode("push","%s",
12844                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12845                 emitcode("push","%s",
12846                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12847                 emitcode("pop","ar3");
12848                 emitcode("pop","ar2");
12849         } else {
12850                 emitcode ("mov","r2,%s",
12851                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12852                 emitcode ("mov","r3,%s",
12853                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12854         }
12855         freeAsmop (handle, NULL, ic, FALSE);
12856
12857         /* make the call */
12858         emitcode ("lcall","MM_UnrestrictedPersist");
12859
12860         {
12861                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12862                 if (rsym->liveFrom != rsym->liveTo) {
12863                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12864                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12865                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12866                 }
12867         }
12868         unsavermask(rsave);
12869 }
12870
12871 /*-----------------------------------------------------------------*/
12872 /* genSystemExecJavaProcess -                                      */
12873 /*-----------------------------------------------------------------*/
12874 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
12875 {
12876         bitVect *rsave ;
12877         operand *handle, *pp;
12878
12879         assert (nparms==2);
12880         /* save registers that need to be saved */
12881         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12882                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12883
12884         pp = parms[0];
12885         handle = parms[1];
12886
12887         /* put the handle in R3-R2 */
12888         aopOp (handle,ic,FALSE,FALSE);
12889         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12890                 emitcode("push","%s",
12891                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12892                 emitcode("push","%s",
12893                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12894                 emitcode("pop","ar3");
12895                 emitcode("pop","ar2");
12896         } else {
12897                 emitcode ("mov","r2,%s",
12898                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12899                 emitcode ("mov","r3,%s",
12900                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12901         }
12902         freeAsmop (handle, NULL, ic, FALSE);
12903
12904         /* put pointer in DPTR */
12905         aopOp (pp,ic,FALSE,FALSE);
12906         if (AOP_TYPE(pp) == AOP_IMMD) {
12907                 emitcode ("mov", "dptr,%s",
12908                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12909         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
12910                 emitcode ("mov","dpl,%s",aopGet(AOP(pp),0,FALSE,FALSE,NULL));
12911                 emitcode ("mov","dph,%s",aopGet(AOP(pp),1,FALSE,FALSE,NULL));
12912                 emitcode ("mov","dpx,%s",aopGet(AOP(pp),2,FALSE,FALSE,NULL));
12913         }
12914         freeAsmop (handle, NULL, ic, FALSE);
12915
12916         /* make the call */
12917         emitcode ("lcall","System_ExecJavaProcess");
12918
12919         /* put result in place */
12920         {
12921                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12922                 if (rsym->liveFrom != rsym->liveTo) {
12923                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12924                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12925                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12926                 }
12927         }
12928
12929         unsavermask(rsave);
12930 }
12931
12932 /*-----------------------------------------------------------------*/
12933 /* genSystemRTCRegisters -                                         */
12934 /*-----------------------------------------------------------------*/
12935 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
12936                                   char *name)
12937 {
12938         bitVect *rsave ;
12939         operand *pp;
12940
12941         assert (nparms==1);
12942         /* save registers that need to be saved */
12943         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12944                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12945
12946         pp=parms[0];
12947         /* put pointer in DPTR */
12948         aopOp (pp,ic,FALSE,FALSE);
12949         if (AOP_TYPE (pp) == AOP_IMMD) {
12950                 emitcode ("mov","dps,#1");
12951                 emitcode ("mov", "dptr,%s",
12952                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12953                 emitcode ("mov","dps,#0");
12954         } else {
12955                 emitcode ("mov","dpl1,%s",
12956                           aopGet(AOP(pp),0,FALSE,FALSE,DP2_RESULT_REG));
12957                 emitcode ("mov","dph1,%s",
12958                           aopGet(AOP(pp),1,FALSE,FALSE,DP2_RESULT_REG));
12959                 emitcode ("mov","dpx1,%s",
12960                           aopGet(AOP(pp),2,FALSE,FALSE,DP2_RESULT_REG));
12961         }
12962         freeAsmop (pp, NULL, ic, FALSE);
12963
12964         /* make the call */
12965         emitcode ("lcall","System_%sRTCRegisters",name);
12966
12967         unsavermask(rsave);
12968 }
12969
12970 /*-----------------------------------------------------------------*/
12971 /* genSystemThreadSleep -                                          */
12972 /*-----------------------------------------------------------------*/
12973 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
12974 {
12975         bitVect *rsave ;
12976         operand *to, *s;
12977
12978         assert (nparms==1);
12979         /* save registers that need to be saved */
12980         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12981                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12982
12983         to = parms[0];
12984         aopOp(to,ic,FALSE,FALSE);
12985         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
12986             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
12987                 emitcode ("push","%s",
12988                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
12989                 emitcode ("push","%s",
12990                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
12991                 emitcode ("push","%s",
12992                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
12993                 emitcode ("push","%s",
12994                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
12995                 emitcode ("pop","ar3");
12996                 emitcode ("pop","ar2");
12997                 emitcode ("pop","ar1");
12998                 emitcode ("pop","ar0");
12999         } else {
13000                 emitcode ("mov","r0,%s",
13001                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
13002                 emitcode ("mov","r1,%s",
13003                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
13004                 emitcode ("mov","r2,%s",
13005                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
13006                 emitcode ("mov","r3,%s",
13007                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
13008         }
13009         freeAsmop (to, NULL, ic, FALSE);
13010
13011         /* suspend in acc */
13012         s = parms[1];
13013         aopOp(s,ic,FALSE,FALSE);
13014         emitcode ("mov","a,%s",
13015                   aopGet(AOP(s),0,FALSE,TRUE,NULL));
13016         freeAsmop (s, NULL, ic, FALSE);
13017
13018         /* make the call */
13019         emitcode ("lcall","System_%s",name);
13020
13021         unsavermask(rsave);
13022 }
13023
13024 /*-----------------------------------------------------------------*/
13025 /* genSystemThreadResume -                                         */
13026 /*-----------------------------------------------------------------*/
13027 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13028 {
13029         bitVect *rsave ;
13030         operand *tid,*pid;
13031
13032         assert (nparms==2);
13033         /* save registers that need to be saved */
13034         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13035                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13036
13037         tid = parms[0];
13038         pid = parms[1];
13039
13040         /* PID in R0 */
13041         aopOp(pid,ic,FALSE,FALSE);
13042         emitcode ("mov","r0,%s",
13043                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
13044         freeAsmop (pid, NULL, ic, FALSE);
13045
13046         /* tid into ACC */
13047         aopOp(tid,ic,FALSE,FALSE);
13048         emitcode ("mov","a,%s",
13049                   aopGet(AOP(tid),0,FALSE,TRUE,DP2_RESULT_REG));
13050         freeAsmop (tid, NULL, ic, FALSE);
13051
13052         emitcode ("lcall","System_ThreadResume");
13053
13054         /* put result into place */
13055         {
13056                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13057                 if (rsym->liveFrom != rsym->liveTo) {
13058                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13059                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13060                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13061                 }
13062         }
13063         unsavermask(rsave);
13064 }
13065
13066 /*-----------------------------------------------------------------*/
13067 /* genSystemProcessResume -                                        */
13068 /*-----------------------------------------------------------------*/
13069 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13070 {
13071         bitVect *rsave ;
13072         operand *pid;
13073
13074         assert (nparms==1);
13075         /* save registers that need to be saved */
13076         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13077                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13078
13079         pid = parms[0];
13080
13081         /* pid into ACC */
13082         aopOp(pid,ic,FALSE,FALSE);
13083         emitcode ("mov","a,%s",
13084                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
13085         freeAsmop (pid, NULL, ic, FALSE);
13086
13087         emitcode ("lcall","System_ProcessResume");
13088
13089         unsavermask(rsave);
13090 }
13091
13092 /*-----------------------------------------------------------------*/
13093 /* genSystem -                                                     */
13094 /*-----------------------------------------------------------------*/
13095 static void genSystem (iCode *ic,int nparms,char *name)
13096 {
13097         assert(nparms == 0);
13098
13099         emitcode ("lcall","System_%s",name);
13100 }
13101
13102 /*-----------------------------------------------------------------*/
13103 /* genSystemPoll -                                                  */
13104 /*-----------------------------------------------------------------*/
13105 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13106 {
13107         bitVect *rsave ;
13108         operand *fp;
13109
13110         assert (nparms==1);
13111         /* save registers that need to be saved */
13112         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13113                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13114
13115         fp = parms[0];
13116         aopOp (fp,ic,FALSE,FALSE);
13117         if (AOP_TYPE (fp) == AOP_IMMD) {
13118                 emitcode ("mov", "dptr,%s",
13119                           aopGet (AOP (fp), 0, TRUE, FALSE, DP2_RESULT_REG));
13120         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13121                 emitcode ("mov","dpl,%s",
13122                           aopGet(AOP(fp),0,FALSE,FALSE,DP2_RESULT_REG));
13123                 emitcode ("mov","dph,%s",
13124                           aopGet(AOP(fp),1,FALSE,FALSE,DP2_RESULT_REG));
13125                 emitcode ("mov","dpx,%s",
13126                           aopGet(AOP(fp),2,FALSE,FALSE,DP2_RESULT_REG));
13127         }
13128         freeAsmop (fp, NULL, ic, FALSE);
13129
13130         emitcode ("lcall","System_%sPoll",name);
13131
13132         /* put result into place */
13133         {
13134                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13135                 if (rsym->liveFrom != rsym->liveTo) {
13136                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13137                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13138                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13139                 }
13140         }
13141         unsavermask(rsave);
13142 }
13143
13144 /*-----------------------------------------------------------------*/
13145 /* genSystemGetCurrentID -                                         */
13146 /*-----------------------------------------------------------------*/
13147 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13148 {
13149         assert (nparms==0);
13150
13151         emitcode ("lcall","System_GetCurrent%sId",name);
13152         /* put result into place */
13153         {
13154                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13155                 if (rsym->liveFrom != rsym->liveTo) {
13156                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13157                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13158                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13159                 }
13160         }
13161 }
13162
13163 /*-----------------------------------------------------------------*/
13164 /* genDummyRead - generate code for dummy read of volatiles        */
13165 /*-----------------------------------------------------------------*/
13166 static void
13167 genDummyRead (iCode * ic)
13168 {
13169   operand *op;
13170   int size, offset;
13171
13172   D(emitcode(";     genDummyRead",""));
13173
13174   op = IC_RIGHT (ic);
13175   if (op && IS_SYMOP (op))
13176     {
13177       aopOp (op, ic, FALSE, FALSE);
13178
13179       /* if the result is a bit */
13180       if (AOP_TYPE (op) == AOP_CRY)
13181         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13182       else
13183         {
13184           /* bit variables done */
13185           /* general case */
13186           size = AOP_SIZE (op);
13187           offset = 0;
13188           while (size--)
13189           {
13190             MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
13191             offset++;
13192           }
13193         }
13194
13195       freeAsmop (op, NULL, ic, TRUE);
13196     }
13197
13198   op = IC_LEFT (ic);
13199   if (op && IS_SYMOP (op))
13200     {
13201       aopOp (op, ic, FALSE, FALSE);
13202
13203       /* if the result is a bit */
13204       if (AOP_TYPE (op) == AOP_CRY)
13205         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13206       else
13207         {
13208           /* bit variables done */
13209           /* general case */
13210           size = AOP_SIZE (op);
13211           offset = 0;
13212           while (size--)
13213           {
13214             MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
13215             offset++;
13216           }
13217         }
13218
13219       freeAsmop (op, NULL, ic, TRUE);
13220     }
13221
13222 }
13223
13224 /*-----------------------------------------------------------------*/
13225 /* genCritical - generate code for start of a critical sequence    */
13226 /*-----------------------------------------------------------------*/
13227 static void
13228 genCritical (iCode *ic)
13229 {
13230   symbol *tlbl = newiTempLabel (NULL);
13231
13232   D(emitcode(";     genCritical",""));
13233
13234   if (IC_RESULT (ic))
13235     aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13236
13237   emitcode ("setb", "c");
13238   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13239   emitcode ("clr", "c");
13240   emitcode ("", "%05d$:", (tlbl->key + 100));
13241
13242   if (IC_RESULT (ic))
13243     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
13244   else
13245     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13246
13247   if (IC_RESULT (ic))
13248     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13249 }
13250
13251 /*-----------------------------------------------------------------*/
13252 /* genEndCritical - generate code for end of a critical sequence   */
13253 /*-----------------------------------------------------------------*/
13254 static void
13255 genEndCritical (iCode *ic)
13256 {
13257   D(emitcode(";     genEndCritical",""));
13258
13259   if (IC_RIGHT (ic))
13260     {
13261       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13262       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13263         {
13264           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13265           emitcode ("mov", "ea,c");
13266         }
13267       else
13268         {
13269           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE, FALSE));
13270           emitcode ("rrc", "a");
13271           emitcode ("mov", "ea,c");
13272         }
13273       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13274     }
13275   else
13276     {
13277       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13278       emitcode ("mov", "ea,c");
13279     }
13280 }
13281
13282
13283
13284 /*-----------------------------------------------------------------*/
13285 /* genBuiltIn - calls the appropriate function to  generating code */
13286 /* for a built in function                                         */
13287 /*-----------------------------------------------------------------*/
13288 static void genBuiltIn (iCode *ic)
13289 {
13290         operand *bi_parms[MAX_BUILTIN_ARGS];
13291         int nbi_parms;
13292         iCode *bi_iCode;
13293         symbol *bif;
13294
13295         /* get all the arguments for a built in function */
13296         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13297
13298         /* which function is it */
13299         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13300         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13301                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13302         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13303                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13304         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13305                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13306         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13307                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13308         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13309                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13310         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13311                 genInp(bi_iCode,nbi_parms,bi_parms);
13312         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13313                 genOutp(bi_iCode,nbi_parms,bi_parms);
13314         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13315                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13316                 /* JavaNative builtIns */
13317         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13318                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13319         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13320                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13321         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13322                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13323         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13324                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13325         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13326                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13327         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13328                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13329         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13330                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13331         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13332                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13333         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13334                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13335         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13336                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13337         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13338                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13339         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13340                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13341         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13342                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13343         } else if (strcmp(bif->name,"MM_Free")==0) {
13344                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13345         } else if (strcmp(bif->name,"MM_Deref")==0) {
13346                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13347         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13348                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13349         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13350                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13351         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13352                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13353         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13354                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13355         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13356                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13357         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
13358                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
13359         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
13360                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
13361         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
13362                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
13363         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13364                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13365         } else if (strcmp(bif->name,"System_SaveThread")==0) {
13366                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13367         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13368                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13369         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
13370                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
13371         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
13372                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
13373         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
13374                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
13375         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
13376                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
13377         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
13378                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
13379         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
13380                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
13381         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
13382                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
13383         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
13384                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
13385         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
13386                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
13387         } else {
13388                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
13389                 return ;
13390         }
13391         return ;
13392 }
13393
13394 /*-----------------------------------------------------------------*/
13395 /* gen390Code - generate code for Dallas 390 based controllers     */
13396 /*-----------------------------------------------------------------*/
13397 void
13398 gen390Code (iCode * lic)
13399 {
13400   iCode *ic;
13401   int cln = 0;
13402
13403   lineHead = lineCurr = NULL;
13404   dptrn[1][0] = "dpl1";
13405   dptrn[1][1] = "dph1";
13406   dptrn[1][2] = "dpx1";
13407
13408   if (options.model == MODEL_FLAT24) {
13409     fReturnSizeDS390 = 5;
13410     fReturn = fReturn24;
13411   } else {
13412     fReturnSizeDS390 = 4;
13413     fReturn = fReturn16;
13414     options.stack10bit=0;
13415   }
13416 #if 1
13417   /* print the allocation information */
13418   if (allocInfo && currFunc)
13419     printAllocInfo (currFunc, codeOutFile);
13420 #endif
13421   /* if debug information required */
13422   if (options.debug && currFunc)
13423     {
13424       debugFile->writeFunction (currFunc, lic);
13425     }
13426   /* stack pointer name */
13427   if (options.useXstack)
13428     spname = "_spx";
13429   else
13430     spname = "sp";
13431
13432
13433   for (ic = lic; ic; ic = ic->next)
13434     {
13435
13436       _G.current_iCode = ic;
13437
13438       if (ic->lineno && cln != ic->lineno)
13439         {
13440           if (options.debug)
13441             {
13442               debugFile->writeCLine (ic);
13443             }
13444           if (!options.noCcodeInAsm) {
13445             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
13446                       printCLine(ic->filename, ic->lineno));
13447           }
13448           cln = ic->lineno;
13449         }
13450       if (options.iCodeInAsm) {
13451         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
13452       }
13453       /* if the result is marked as
13454          spilt and rematerializable or code for
13455          this has already been generated then
13456          do nothing */
13457       if (resultRemat (ic) || ic->generated)
13458         continue;
13459
13460       /* depending on the operation */
13461       switch (ic->op)
13462         {
13463         case '!':
13464           genNot (ic);
13465           break;
13466
13467         case '~':
13468           genCpl (ic);
13469           break;
13470
13471         case UNARYMINUS:
13472           genUminus (ic);
13473           break;
13474
13475         case IPUSH:
13476           genIpush (ic);
13477           break;
13478
13479         case IPOP:
13480           /* IPOP happens only when trying to restore a
13481              spilt live range, if there is an ifx statement
13482              following this pop then the if statement might
13483              be using some of the registers being popped which
13484              would destory the contents of the register so
13485              we need to check for this condition and handle it */
13486           if (ic->next &&
13487               ic->next->op == IFX &&
13488               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
13489             genIfx (ic->next, ic);
13490           else
13491             genIpop (ic);
13492           break;
13493
13494         case CALL:
13495           genCall (ic);
13496           break;
13497
13498         case PCALL:
13499           genPcall (ic);
13500           break;
13501
13502         case FUNCTION:
13503           genFunction (ic);
13504           break;
13505
13506         case ENDFUNCTION:
13507           genEndFunction (ic);
13508           break;
13509
13510         case RETURN:
13511           genRet (ic);
13512           break;
13513
13514         case LABEL:
13515           genLabel (ic);
13516           break;
13517
13518         case GOTO:
13519           genGoto (ic);
13520           break;
13521
13522         case '+':
13523           genPlus (ic);
13524           break;
13525
13526         case '-':
13527           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
13528             genMinus (ic);
13529           break;
13530
13531         case '*':
13532           genMult (ic);
13533           break;
13534
13535         case '/':
13536           genDiv (ic);
13537           break;
13538
13539         case '%':
13540           genMod (ic);
13541           break;
13542
13543         case '>':
13544           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
13545           break;
13546
13547         case '<':
13548           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
13549           break;
13550
13551         case LE_OP:
13552         case GE_OP:
13553         case NE_OP:
13554
13555           /* note these two are xlated by algebraic equivalence
13556              during parsing SDCC.y */
13557           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13558                   "got '>=' or '<=' shouldn't have come here");
13559           break;
13560
13561         case EQ_OP:
13562           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
13563           break;
13564
13565         case AND_OP:
13566           genAndOp (ic);
13567           break;
13568
13569         case OR_OP:
13570           genOrOp (ic);
13571           break;
13572
13573         case '^':
13574           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
13575           break;
13576
13577         case '|':
13578           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
13579           break;
13580
13581         case BITWISEAND:
13582           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
13583           break;
13584
13585         case INLINEASM:
13586           genInline (ic);
13587           break;
13588
13589         case RRC:
13590           genRRC (ic);
13591           break;
13592
13593         case RLC:
13594           genRLC (ic);
13595           break;
13596
13597         case GETHBIT:
13598           genGetHbit (ic);
13599           break;
13600
13601         case LEFT_OP:
13602           genLeftShift (ic);
13603           break;
13604
13605         case RIGHT_OP:
13606           genRightShift (ic);
13607           break;
13608
13609         case GET_VALUE_AT_ADDRESS:
13610           genPointerGet (ic,hasInc(IC_LEFT(ic),ic, getSize(operandType(IC_RESULT(ic)))));
13611           break;
13612
13613         case '=':
13614           if (POINTER_SET (ic))
13615             genPointerSet (ic,hasInc(IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
13616           else
13617             genAssign (ic);
13618           break;
13619
13620         case IFX:
13621           genIfx (ic, NULL);
13622           break;
13623
13624         case ADDRESS_OF:
13625           genAddrOf (ic);
13626           break;
13627
13628         case JUMPTABLE:
13629           genJumpTab (ic);
13630           break;
13631
13632         case CAST:
13633           genCast (ic);
13634           break;
13635
13636         case RECEIVE:
13637           genReceive (ic);
13638           break;
13639
13640         case SEND:
13641           if (ic->builtinSEND) genBuiltIn(ic);
13642           else addSet (&_G.sendSet, ic);
13643           break;
13644
13645         case DUMMY_READ_VOLATILE:
13646           genDummyRead (ic);
13647           break;
13648
13649         case CRITICAL:
13650           genCritical (ic);
13651           break;
13652
13653         case ENDCRITICAL:
13654           genEndCritical (ic);
13655           break;
13656
13657         case SWAP:
13658           genSwap (ic);
13659           break;
13660
13661 #if 0 // obsolete, and buggy for != xdata
13662         case ARRAYINIT:
13663             genArrayInit(ic);
13664             break;
13665 #endif
13666
13667         default:
13668           ic = ic;
13669         }
13670     }
13671
13672
13673   /* now we are ready to call the
13674      peep hole optimizer */
13675   if (!options.nopeep)
13676     peepHole (&lineHead);
13677
13678   /* now do the actual printing */
13679   printLine (lineHead, codeOutFile);
13680   return;
13681 }