* src/SDCC.lex (doPragma): added pragma disable_warning <nnn>
[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, const 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), fmt, ap);
163     }
164   else
165     {
166       tvsprintf (lb, sizeof(lb), fmt, ap);
167     }
168
169   while (isspace (*lbp))
170     {
171       lbp++;
172     }
173
174   if (lbp && *lbp)
175     {
176       lineCurr = (lineCurr ?
177                   connectLine (lineCurr, newLineNode (lb)) :
178                   (lineHead = newLineNode (lb)));
179     }
180
181   lineCurr->isInline = _G.inLine;
182   lineCurr->isDebug = _G.debugLine;
183   lineCurr->ic = _G.current_iCode;
184   lineCurr->aln = ds390newAsmLineNode(_currentDPS);
185   va_end (ap);
186 }
187
188 /*-----------------------------------------------------------------*/
189 /* ds390_emitDebuggerSymbol - associate the current code location  */
190 /*   with a debugger symbol                                        */
191 /*-----------------------------------------------------------------*/
192 void
193 ds390_emitDebuggerSymbol (char * debugSym)
194 {
195   _G.debugLine = 1;
196   emitcode ("", "%s ==.", debugSym);
197   _G.debugLine = 0;
198 }
199
200 //
201 // Move the passed value into A unless it is already there.
202 //
203 static void
204 _movA(const char *s)
205 {
206     if (strcmp(s,"a") && strcmp(s,"acc"))
207     {
208         emitcode("mov","a,%s",s);
209     }
210 }
211
212 //
213 // Move the passed value into B unless it is already there.
214 //
215 static void
216 _movB(const char *s)
217 {
218     if (strcmp(s,"b"))
219     {
220         emitcode("mov","b,%s",s);
221     }
222 }
223
224 /*-----------------------------------------------------------------*/
225 /* getFreePtr - returns r0 or r1 whichever is free or can be pushed */
226 /*-----------------------------------------------------------------*/
227 static regs *
228 getFreePtr (iCode * ic, asmop ** aopp, bool result)
229 {
230   bool r0iu, r1iu;
231   bool r0ou, r1ou;
232
233   /* the logic: if r0 & r1 used in the instruction
234      then we are in trouble otherwise */
235
236   /* first check if r0 & r1 are used by this
237      instruction, in which case we are in trouble */
238   r0iu = bitVectBitValue (ic->rUsed, R0_IDX);
239   r1iu = bitVectBitValue (ic->rUsed, R1_IDX);
240   if (r0iu && r1iu) {
241       goto endOfWorld;
242     }
243
244   r0ou = bitVectBitValue (ic->rMask, R0_IDX);
245   r1ou = bitVectBitValue (ic->rMask, R1_IDX);
246
247   /* if no usage of r0 then return it */
248   if (!r0iu && !r0ou)
249     {
250       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
251       (*aopp)->type = AOP_R0;
252
253       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
254     }
255
256   /* if no usage of r1 then return it */
257   if (!r1iu && !r1ou)
258     {
259       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
260       (*aopp)->type = AOP_R1;
261
262       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R1_IDX);
263     }
264
265   /* now we know they both have usage */
266   /* if r0 not used in this instruction */
267   if (!r0iu)
268     {
269       /* push it if not already pushed */
270       if (!_G.r0Pushed)
271         {
272           emitcode ("push", "%s",
273                     ds390_regWithIdx (R0_IDX)->dname);
274           _G.r0Pushed++;
275         }
276
277       ic->rUsed = bitVectSetBit (ic->rUsed, R0_IDX);
278       (*aopp)->type = AOP_R0;
279
280       return (*aopp)->aopu.aop_ptr = ds390_regWithIdx (R0_IDX);
281     }
282
283   /* if r1 not used then */
284
285   if (!r1iu)
286     {
287       /* push it if not already pushed */
288       if (!_G.r1Pushed)
289         {
290           emitcode ("push", "%s",
291                     ds390_regWithIdx (R1_IDX)->dname);
292           _G.r1Pushed++;
293         }
294
295       ic->rUsed = bitVectSetBit (ic->rUsed, R1_IDX);
296       (*aopp)->type = AOP_R1;
297       return ds390_regWithIdx (R1_IDX);
298     }
299
300 endOfWorld:
301   /* I said end of world but not quite end of world yet */
302   /* if this is a result then we can push it on the stack */
303   if (result)
304     {
305       (*aopp)->type = AOP_STK;
306       return NULL;
307     }
308
309   /* other wise this is true end of the world */
310   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
311           "getFreePtr should never reach here");
312   exit (1);
313
314   return NULL; // notreached, but makes compiler happy.
315 }
316
317 /*-----------------------------------------------------------------*/
318 /* newAsmop - creates a new asmOp                                  */
319 /*-----------------------------------------------------------------*/
320 static asmop *
321 newAsmop (short type)
322 {
323   asmop *aop;
324
325   aop = Safe_calloc (1, sizeof (asmop));
326   aop->type = type;
327   return aop;
328 }
329
330
331 /*-----------------------------------------------------------------*/
332 /* genSetDPTR: generate code to select which DPTR is in use (zero  */
333 /* selects standard DPTR (DPL/DPH/DPX), non-zero selects DS390     */
334 /* alternate DPTR (DPL1/DPH1/DPX1).          */
335 /*-----------------------------------------------------------------*/
336 static void
337 genSetDPTR (int n)
338 {
339
340   /* If we are doing lazy evaluation, simply note the desired
341    * change, but don't emit any code yet.
342    */
343   if (_lazyDPS)
344     {
345       _desiredDPS = n;
346       return;
347     }
348
349   if (!n)
350     {
351       emitcode ("mov", "dps,#0");
352     }
353   else
354     {
355       TR_DPTR("#1");
356       emitcode ("mov", "dps,#1");
357     }
358 }
359
360 /*-----------------------------------------------------------------*/
361 /* _startLazyDPSEvaluation: call to start doing lazy DPS evaluation */
362 /*                   */
363 /* Any code that operates on DPTR (NB: not on the individual     */
364 /* components, like DPH) *must* call _flushLazyDPS() before using  */
365 /* DPTR within a lazy DPS evaluation block.        */
366 /*                   */
367 /* Note that aopPut and aopGet already contain the proper calls to */
368 /* _flushLazyDPS, so it is safe to use these calls within a lazy   */
369 /* DPS evaluation block.             */
370 /*                   */
371 /* Also, _flushLazyDPS must be called before any flow control      */
372 /* operations that could potentially branch out of the block.    */
373 /*                         */
374 /* Lazy DPS evaluation is simply an optimization (though an      */
375 /* important one), so if in doubt, leave it out.       */
376 /*-----------------------------------------------------------------*/
377 static void
378 _startLazyDPSEvaluation (void)
379 {
380   _currentDPS = 0;
381   _desiredDPS = 0;
382 #ifdef BETTER_LITERAL_SHIFT
383   _lazyDPS++;
384 #else
385   _lazyDPS = 1;
386 #endif
387 }
388
389 /*-----------------------------------------------------------------*/
390 /* _flushLazyDPS: emit code to force the actual DPS setting to the */
391 /* desired one. Call before using DPTR within a lazy DPS evaluation */
392 /* block.                */
393 /*-----------------------------------------------------------------*/
394 static void
395 _flushLazyDPS (void)
396 {
397   if (!_lazyDPS)
398     {
399       /* nothing to do. */
400       return;
401     }
402
403   if (_desiredDPS != _currentDPS)
404     {
405       if (_desiredDPS)
406         {
407           emitcode ("inc", "dps");
408         }
409       else
410         {
411           emitcode ("dec", "dps");
412         }
413       _currentDPS = _desiredDPS;
414     }
415 }
416
417 /*-----------------------------------------------------------------*/
418 /* _endLazyDPSEvaluation: end lazy DPS evaluation block.     */
419 /*                   */
420 /* Forces us back to the safe state (standard DPTR selected).    */
421 /*-----------------------------------------------------------------*/
422 static void
423 _endLazyDPSEvaluation (void)
424 {
425 #ifdef BETTER_LITERAL_SHIFT
426   _lazyDPS--;
427 #else
428   _lazyDPS = 0;
429 #endif
430   if (!_lazyDPS)
431   {
432     if (_currentDPS)
433     {
434       genSetDPTR (0);
435       _flushLazyDPS ();
436     }
437     _currentDPS = 0;
438     _desiredDPS = 0;
439   }
440 }
441
442
443
444 /*-----------------------------------------------------------------*/
445 /* pointerCode - returns the code for a pointer type               */
446 /*-----------------------------------------------------------------*/
447 static int
448 pointerCode (sym_link * etype)
449 {
450
451   return PTR_TYPE (SPEC_OCLS (etype));
452
453 }
454
455 /*-----------------------------------------------------------------*/
456 /* leftRightUseAcc - returns size of accumulator use by operands   */
457 /*-----------------------------------------------------------------*/
458 static int
459 leftRightUseAcc(iCode *ic)
460 {
461   operand *op;
462   int size;
463   int accuseSize = 0;
464   int accuse = 0;
465
466   if (!ic)
467     {
468       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
469               "null iCode pointer");
470       return 0;
471     }
472
473   if (ic->op == IFX)
474     {
475       op = IC_COND (ic);
476       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
477         {
478           accuse = 1;
479           size = getSize (OP_SYMBOL (op)->type);
480           if (size>accuseSize)
481             accuseSize = size;
482         }
483     }
484   else if (ic->op == JUMPTABLE)
485     {
486       op = IC_JTCOND (ic);
487       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
488         {
489           accuse = 1;
490           size = getSize (OP_SYMBOL (op)->type);
491           if (size>accuseSize)
492             accuseSize = size;
493         }
494     }
495   else
496     {
497       op = IC_LEFT (ic);
498       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
499         {
500           accuse = 1;
501           size = getSize (OP_SYMBOL (op)->type);
502           if (size>accuseSize)
503             accuseSize = size;
504         }
505       op = IC_RIGHT (ic);
506       if (IS_SYMOP (op) && OP_SYMBOL (op) && OP_SYMBOL (op)->accuse)
507         {
508           accuse = 1;
509           size = getSize (OP_SYMBOL (op)->type);
510           if (size>accuseSize)
511             accuseSize = size;
512         }
513     }
514
515   if (accuseSize)
516     return accuseSize;
517   else
518     return accuse;
519 }
520
521 /*-----------------------------------------------------------------*/
522 /* aopForSym - for a true symbol                                   */
523 /*-----------------------------------------------------------------*/
524 static asmop *
525 aopForSym (iCode * ic, symbol * sym, bool result, bool useDP2)
526 {
527   asmop *aop;
528   memmap *space = SPEC_OCLS (sym->etype);
529   int accuse = leftRightUseAcc (ic);
530
531   /* if already has one */
532   if (sym->aop)
533     {
534       if ((sym->aop->type == AOP_DPTR && useDP2)
535           || (sym->aop->type == AOP_DPTR2 && !useDP2))
536         sym->aop = NULL;
537       else
538         return sym->aop;
539     }
540
541   /* assign depending on the storage class */
542   /* if it is on the stack or indirectly addressable */
543   /* space we need to assign either r0 or r1 to it   */
544   if ((sym->onStack && !options.stack10bit) || sym->iaccess)
545     {
546       sym->aop = aop = newAsmop (0);
547       aop->aopu.aop_ptr = getFreePtr (ic, &aop, result);
548       aop->size = getSize (sym->type);
549
550       /* now assign the address of the variable to
551          the pointer register */
552       if (aop->type != AOP_STK)
553         {
554
555           if (sym->onStack)
556             {
557               if (_G.accInUse || accuse)
558                 emitcode ("push", "acc");
559
560               if (_G.bInUse || (accuse>1))
561                 emitcode ("push", "b");
562
563               emitcode ("mov", "a,_bp");
564               emitcode ("add", "a,#!constbyte",
565                         ((sym->stack < 0) ?
566                          ((char) (sym->stack - _G.nRegsSaved)) :
567                          ((char) sym->stack)) & 0xff);
568               emitcode ("mov", "%s,a",
569                         aop->aopu.aop_ptr->name);
570
571               if (_G.bInUse || (accuse>1))
572                 emitcode ("pop", "b");
573
574               if (_G.accInUse || accuse)
575                 emitcode ("pop", "acc");
576             }
577           else
578             emitcode ("mov", "%s,#%s",
579                       aop->aopu.aop_ptr->name,
580                       sym->rname);
581           aop->paged = space->paged;
582         }
583       else
584         aop->aopu.aop_stk = sym->stack;
585       return aop;
586     }
587
588   if (sym->onStack && options.stack10bit)
589     {
590         short stack_val = -((sym->stack < 0) ?
591                             ((short) (sym->stack - _G.nRegsSaved)) :
592                             ((short) sym->stack)) ;
593         if (useDP2 && _G.dptr1InUse) {
594             emitcode ("push","dpl1");
595             emitcode ("push","dph1");
596             emitcode ("push","dpx1");
597         } else if (_G.dptrInUse ) {
598             emitcode ("push","dpl");
599             emitcode ("push","dph");
600             emitcode ("push","dpx");
601         }
602       /* It's on the 10 bit stack, which is located in
603        * far data space.
604        */
605         if (stack_val < 0 && stack_val > -5) { /* between -5 & -1 */
606             if (useDP2) {
607                 if (options.model == MODEL_FLAT24)
608                 {
609                     emitcode ("mov", "dpx1,#!constbyte",
610                               (options.stack_loc >> 16) & 0xff);
611                 }
612                 emitcode ("mov", "dph1,_bpx+1");
613
614                 emitcode ("mov", "dpl1,_bpx");
615                 emitcode ("mov","dps,#1");
616             } else {
617                 if (options.model == MODEL_FLAT24)
618                 {
619                     emitcode ("mov", "dpx,#!constbyte",
620                               (options.stack_loc >> 16) & 0xff);
621                 }
622                 emitcode ("mov", "dph,_bpx+1");
623                 emitcode ("mov", "dpl,_bpx");
624             }
625             stack_val = -stack_val;
626             while (stack_val--) {
627                 emitcode ("inc","dptr");
628             }
629             if (useDP2) {
630                 emitcode("mov","dps,#0");
631             }
632         }  else {
633             if (_G.accInUse || accuse)
634                 emitcode ("push", "acc");
635
636             if (_G.bInUse || (accuse>1))
637                 emitcode ("push", "b");
638
639             emitcode ("mov", "a,_bpx");
640             emitcode ("clr","c");
641             emitcode ("subb", "a,#!constbyte", stack_val & 0xff);
642             emitcode ("mov","b,a");
643             emitcode ("mov","a,_bpx+1");
644             emitcode ("subb","a,#!constbyte",(stack_val >> 8) & 0xff);
645             if (useDP2) {
646                 if (options.model == MODEL_FLAT24)
647                 {
648                     emitcode ("mov", "dpx1,#!constbyte",
649                               (options.stack_loc >> 16) & 0xff);
650                 }
651                 emitcode ("mov", "dph1,a");
652                 emitcode ("mov", "dpl1,b");
653             } else {
654                 if (options.model == MODEL_FLAT24)
655                 {
656                     emitcode ("mov", "dpx,#!constbyte",
657                               (options.stack_loc >> 16) & 0xff);
658                 }
659                 emitcode ("mov", "dph,a");
660                 emitcode ("mov", "dpl,b");
661             }
662
663             if (_G.bInUse || (accuse>1))
664                 emitcode ("pop", "b");
665
666             if (_G.accInUse || accuse)
667                 emitcode ("pop", "acc");
668         }
669         sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
670         aop->size = getSize (sym->type);
671         return aop;
672     }
673
674   /* if in bit space */
675   if (IN_BITSPACE (space))
676     {
677       sym->aop = aop = newAsmop (AOP_CRY);
678       aop->aopu.aop_dir = sym->rname;
679       aop->size = getSize (sym->type);
680       return aop;
681     }
682   /* if it is in direct space */
683   if (IN_DIRSPACE (space))
684     {
685       sym->aop = aop = newAsmop (AOP_DIR);
686       aop->aopu.aop_dir = sym->rname;
687       aop->size = getSize (sym->type);
688       return aop;
689     }
690
691   /* special case for a function */
692   if (IS_FUNC (sym->type) && !(sym->isitmp))
693     {
694       sym->aop = aop = newAsmop (AOP_IMMD);
695       aop->aopu.aop_immd.aop_immd1 = Safe_strdup(sym->rname);
696       aop->size = FPTRSIZE;
697       return aop;
698     }
699
700   /* only remaining is far space */
701   /* in which case DPTR gets the address */
702   sym->aop = aop = newAsmop ((short) (useDP2 ? AOP_DPTR2 : AOP_DPTR));
703   if (useDP2)
704     {
705       genSetDPTR (1);
706       _flushLazyDPS ();
707       emitcode ("mov", "dptr,#%s", sym->rname);
708       genSetDPTR (0);
709     }
710   else
711     {
712       emitcode ("mov", "dptr,#%s", sym->rname);
713     }
714   aop->size = getSize (sym->type);
715
716   /* if it is in code space */
717   if (IN_CODESPACE (space))
718     aop->code = 1;
719
720   return aop;
721 }
722
723 /*-----------------------------------------------------------------*/
724 /* aopForRemat - rematerialzes an object                           */
725 /*-----------------------------------------------------------------*/
726 static asmop *
727 aopForRemat (symbol * sym)
728 {
729   iCode *ic = sym->rematiCode;
730   asmop *aop = newAsmop (AOP_IMMD);
731   int ptr_type = 0;
732   int val = 0;
733
734   for (;;)
735     {
736       if (ic->op == '+')
737         val += (int) operandLitValue (IC_RIGHT (ic));
738       else if (ic->op == '-')
739         val -= (int) operandLitValue (IC_RIGHT (ic));
740       else if (IS_CAST_ICODE(ic)) {
741               sym_link *from_type = operandType(IC_RIGHT(ic));
742               aop->aopu.aop_immd.from_cast_remat = 1;
743               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
744               ptr_type = DCL_TYPE(from_type);
745               if (ptr_type == IPOINTER) {
746                 // bug #481053
747                 ptr_type = POINTER;
748               }
749               continue ;
750       } else break;
751
752       ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
753     }
754
755   if (val)
756   {
757       SNPRINTF (buffer, sizeof(buffer),
758                 "(%s %c 0x%04x)",
759                 OP_SYMBOL (IC_LEFT (ic))->rname,
760                 val >= 0 ? '+' : '-',
761                 abs (val) & 0xffffff);
762   }
763   else
764   {
765       if (IS_ASSIGN_ICODE(ic) && isOperandLiteral(IC_RIGHT(ic)))
766       {
767           SNPRINTF(buffer, sizeof(buffer),
768                    "0x%x",(int) operandLitValue (IC_RIGHT (ic)));
769       }
770       else
771       {
772           strncpyz (buffer, OP_SYMBOL (IC_LEFT (ic))->rname, sizeof(buffer));
773       }
774   }
775
776   aop->aopu.aop_immd.aop_immd1 = Safe_strdup(buffer);
777   /* set immd2 field if required */
778   if (aop->aopu.aop_immd.from_cast_remat)
779   {
780       tsprintf(buffer, sizeof(buffer), "#!constbyte",ptr_type);
781       aop->aopu.aop_immd.aop_immd2 = Safe_strdup(buffer);
782   }
783
784   return aop;
785 }
786
787 /*-----------------------------------------------------------------*/
788 /* aopHasRegs - returns true if aop has regs between from-to       */
789 /*-----------------------------------------------------------------*/
790 static int aopHasRegs(asmop *aop, int from, int to)
791 {
792     int size =0;
793
794     if (aop->type != AOP_REG) return 0; /* if not assigned to regs */
795
796     for (; size < aop->size ; size++) {
797         int reg;
798         for (reg = from ; reg <= to ; reg++)
799             if (aop->aopu.aop_reg[size] == ds390_regWithIdx(reg)) return 1;
800     }
801     return 0;
802 }
803
804 /*-----------------------------------------------------------------*/
805 /* regsInCommon - two operands have some registers in common       */
806 /*-----------------------------------------------------------------*/
807 static bool
808 regsInCommon (operand * op1, operand * op2)
809 {
810   symbol *sym1, *sym2;
811   int i;
812
813   /* if they have registers in common */
814   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
815     return FALSE;
816
817   sym1 = OP_SYMBOL (op1);
818   sym2 = OP_SYMBOL (op2);
819
820   if (sym1->nRegs == 0 || sym2->nRegs == 0)
821     return FALSE;
822
823   for (i = 0; i < sym1->nRegs; i++)
824     {
825       int j;
826       if (!sym1->regs[i])
827         continue;
828
829       for (j = 0; j < sym2->nRegs; j++)
830         {
831           if (!sym2->regs[j])
832             continue;
833
834           if (sym2->regs[j] == sym1->regs[i])
835             return TRUE;
836         }
837     }
838
839   return FALSE;
840 }
841
842 /*-----------------------------------------------------------------*/
843 /* operandsEqu - equivalent                                        */
844 /*-----------------------------------------------------------------*/
845 static bool
846 operandsEqu (operand * op1, operand * op2)
847 {
848   symbol *sym1, *sym2;
849
850   /* if they not symbols */
851   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
852     return FALSE;
853
854   sym1 = OP_SYMBOL (op1);
855   sym2 = OP_SYMBOL (op2);
856
857   /* if both are itemps & one is spilt
858      and the other is not then false */
859   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
860       sym1->isspilt != sym2->isspilt)
861     return FALSE;
862
863   /* if they are the same */
864   if (sym1 == sym2)
865     return TRUE;
866
867   if (sym1->rname[0] && sym2->rname[0]
868       && strcmp (sym1->rname, sym2->rname) == 0)
869     return TRUE;
870
871   /* if left is a tmp & right is not */
872   if (IS_ITEMP (op1) &&
873       !IS_ITEMP (op2) &&
874       sym1->isspilt &&
875       (sym1->usl.spillLoc == sym2))
876     return TRUE;
877
878   if (IS_ITEMP (op2) &&
879       !IS_ITEMP (op1) &&
880       sym2->isspilt &&
881       sym1->level > 0 &&
882       (sym2->usl.spillLoc == sym1))
883     return TRUE;
884
885   /* are they spilt to the same location */
886   if (IS_ITEMP (op2) &&
887       IS_ITEMP (op1) &&
888       sym2->isspilt &&
889       sym1->isspilt &&
890       (sym1->usl.spillLoc == sym2->usl.spillLoc))
891     return TRUE;
892
893   return FALSE;
894 }
895
896 /*-----------------------------------------------------------------*/
897 /* sameRegs - two asmops have the same registers                   */
898 /*-----------------------------------------------------------------*/
899 static bool
900 sameRegs (asmop * aop1, asmop * aop2)
901 {
902   int i;
903
904   if (aop1 == aop2)
905     {
906       if (aop1->type == AOP_DPTR || aop1->type == AOP_DPTR2)
907         {
908           return FALSE;
909         }
910       return TRUE;
911     }
912
913   if (aop1->type != AOP_REG ||
914       aop2->type != AOP_REG)
915     return FALSE;
916
917   if (aop1->size != aop2->size)
918     return FALSE;
919
920   for (i = 0; i < aop1->size; i++)
921     if (aop1->aopu.aop_reg[i] !=
922         aop2->aopu.aop_reg[i])
923       return FALSE;
924
925   return TRUE;
926 }
927
928 /*-----------------------------------------------------------------*/
929 /* aopOp - allocates an asmop for an operand  :                    */
930 /*-----------------------------------------------------------------*/
931 static void
932 aopOp (operand * op, iCode * ic, bool result, bool useDP2)
933 {
934   asmop *aop;
935   symbol *sym;
936   int i;
937
938   if (!op)
939     return;
940
941   /* if this a literal */
942   if (IS_OP_LITERAL (op))
943     {
944       op->aop = aop = newAsmop (AOP_LIT);
945       aop->aopu.aop_lit = op->operand.valOperand;
946       aop->size = getSize (operandType (op));
947       return;
948     }
949
950   /* if already has a asmop then continue */
951   if (op->aop)
952     {
953       if ((op->aop->type == AOP_DPTR && useDP2)
954           || (op->aop->type == AOP_DPTR2 && !useDP2))
955         op->aop = NULL;
956       else
957         return;
958     }
959
960   /* if the underlying symbol has a aop */
961   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
962     {
963       op->aop = OP_SYMBOL (op)->aop;
964       if ((op->aop->type == AOP_DPTR && useDP2)
965           || (op->aop->type == AOP_DPTR2 && !useDP2))
966         op->aop = NULL;
967       else
968         return;
969     }
970
971   /* if this is a true symbol */
972   if (IS_TRUE_SYMOP (op))
973     {
974       op->aop = aopForSym (ic, OP_SYMBOL (op), result, useDP2);
975       return;
976     }
977
978   /* this is a temporary : this has
979      only four choices :
980      a) register
981      b) spillocation
982      c) rematerialize
983      d) conditional
984      e) can be a return use only */
985
986   sym = OP_SYMBOL (op);
987
988   /* if the type is a conditional */
989   if (sym->regType == REG_CND)
990     {
991       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
992       aop->size = 0;
993       return;
994     }
995
996   /* if it is spilt then two situations
997      a) is rematerialize
998      b) has a spill location */
999   if (sym->isspilt || sym->nRegs == 0)
1000     {
1001
1002       /* rematerialize it NOW */
1003       if (sym->remat)
1004         {
1005           sym->aop = op->aop = aop =
1006             aopForRemat (sym);
1007           aop->size = getSize (sym->type);
1008           return;
1009         }
1010
1011       if (sym->accuse)
1012         {
1013           int i;
1014           aop = op->aop = sym->aop = newAsmop (AOP_ACC);
1015           aop->size = getSize (sym->type);
1016           for (i = 0; i < 2; i++)
1017             aop->aopu.aop_str[i] = accUse[i];
1018           return;
1019         }
1020
1021       if (sym->ruonly)
1022         {
1023           int i;
1024
1025           if (useDP2)
1026             {
1027               /* a AOP_STR uses DPTR, but DPTR is already in use;
1028                * we're just hosed.
1029                */
1030                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"AOP_STR with DPTR in use!");
1031             }
1032
1033           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1034           aop->size = getSize (sym->type);
1035           for (i = 0; i < fReturnSizeDS390; i++)
1036             aop->aopu.aop_str[i] = fReturn[i];
1037           return;
1038         }
1039
1040       if (sym->dptr) { /* has been allocated to a DPTRn */
1041           aop = op->aop = sym->aop = newAsmop (AOP_DPTRn);
1042           aop->size = getSize (sym->type);
1043           aop->aopu.dptr = sym->dptr;
1044           return ;
1045       }
1046
1047       if (sym->usl.spillLoc)
1048         {
1049           if (getSize(sym->type) != getSize(sym->usl.spillLoc->type))
1050             {
1051               /* force a new aop if sizes differ */
1052               sym->usl.spillLoc->aop = NULL;
1053             }
1054           sym->aop = op->aop = aop =
1055                      aopForSym (ic, sym->usl.spillLoc, result, useDP2);
1056           aop->size = getSize (sym->type);
1057           return;
1058         }
1059
1060       /* else must be a dummy iTemp */
1061       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1062       aop->size = getSize (sym->type);
1063       return;
1064     }
1065
1066   /* must be in a register */
1067   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1068   aop->size = sym->nRegs;
1069   for (i = 0; i < sym->nRegs; i++)
1070     aop->aopu.aop_reg[i] = sym->regs[i];
1071 }
1072
1073 /*-----------------------------------------------------------------*/
1074 /* freeAsmop - free up the asmop given to an operand               */
1075 /*----------------------------------------------------------------*/
1076 static void
1077 freeAsmop (operand * op, asmop * aaop, iCode * ic, bool pop)
1078 {
1079   asmop *aop;
1080
1081   if (!op)
1082     aop = aaop;
1083   else
1084     aop = op->aop;
1085
1086   if (!aop)
1087     return;
1088
1089   if (aop->freed)
1090     goto dealloc;
1091
1092   aop->freed = 1;
1093
1094   /* depending on the asmop type only three cases need work AOP_RO
1095      , AOP_R1 && AOP_STK */
1096   switch (aop->type)
1097     {
1098     case AOP_R0:
1099       if (_G.r0Pushed)
1100         {
1101           if (pop)
1102             {
1103               emitcode ("pop", "ar0");
1104               _G.r0Pushed--;
1105             }
1106         }
1107       bitVectUnSetBit (ic->rUsed, R0_IDX);
1108       break;
1109
1110     case AOP_R1:
1111       if (_G.r1Pushed)
1112         {
1113           if (pop)
1114             {
1115               emitcode ("pop", "ar1");
1116               _G.r1Pushed--;
1117             }
1118         }
1119       bitVectUnSetBit (ic->rUsed, R1_IDX);
1120       break;
1121
1122     case AOP_STK:
1123       {
1124         int sz = aop->size;
1125         int stk = aop->aopu.aop_stk + aop->size;
1126         bitVectUnSetBit (ic->rUsed, R0_IDX);
1127         bitVectUnSetBit (ic->rUsed, R1_IDX);
1128
1129         getFreePtr (ic, &aop, FALSE);
1130
1131         if (options.stack10bit)
1132           {
1133             /* I'm not sure what to do here yet... */
1134             /* #STUB */
1135             fprintf (stderr,
1136                      "*** Warning: probably generating bad code for "
1137                      "10 bit stack mode.\n");
1138           }
1139
1140         if (stk)
1141           {
1142             emitcode ("mov", "a,_bp");
1143             emitcode ("add", "a,#!constbyte", ((char) stk) & 0xff);
1144             emitcode ("mov", "%s,a", aop->aopu.aop_ptr->name);
1145           }
1146         else
1147           {
1148             emitcode ("mov", "%s,_bp", aop->aopu.aop_ptr->name);
1149           }
1150
1151         while (sz--)
1152           {
1153             emitcode ("pop", "acc");
1154             emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1155             if (!sz)
1156               break;
1157             emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1158           }
1159         op->aop = aop;
1160         freeAsmop (op, NULL, ic, TRUE);
1161         if (_G.r0Pushed)
1162           {
1163             emitcode ("pop", "ar0");
1164             _G.r0Pushed--;
1165           }
1166
1167         if (_G.r1Pushed)
1168           {
1169             emitcode ("pop", "ar1");
1170             _G.r1Pushed--;
1171           }
1172       }
1173     case AOP_DPTR2:
1174         if (_G.dptr1InUse) {
1175             emitcode ("pop","dpx1");
1176             emitcode ("pop","dph1");
1177             emitcode ("pop","dpl1");
1178         }
1179         break;
1180     case AOP_DPTR:
1181         if (_G.dptrInUse) {
1182             emitcode ("pop","dpx");
1183             emitcode ("pop","dph");
1184             emitcode ("pop","dpl");
1185         }
1186         break;
1187     }
1188 dealloc:
1189   /* all other cases just dealloc */
1190   if (op)
1191     {
1192       op->aop = NULL;
1193       if (IS_SYMOP (op))
1194         {
1195           OP_SYMBOL (op)->aop = NULL;
1196           /* if the symbol has a spill */
1197           if (SPIL_LOC (op))
1198             SPIL_LOC (op)->aop = NULL;
1199         }
1200     }
1201 }
1202
1203 #define DEFAULT_ACC_WARNING 0
1204 static int saveAccWarn = DEFAULT_ACC_WARNING;
1205
1206 /*-------------------------------------------------------------------*/
1207 /* aopGet - for fetching value of the aop                            */
1208 /*                                                                   */
1209 /* Set saveAcc to NULL if you are sure it is OK to clobber the value */
1210 /* in the accumulator. Set it to the name of a free register         */
1211 /* if acc must be preserved; the register will be used to preserve   */
1212 /* acc temporarily and to return the result byte.                    */
1213 /*-------------------------------------------------------------------*/
1214
1215 static char *
1216 aopGet (asmop *aop,
1217         int   offset,
1218         bool  bit16,
1219         bool  dname,
1220         char  *saveAcc)
1221 {
1222   /* offset is greater than
1223      size then zero */
1224   if (offset > (aop->size - 1) &&
1225       aop->type != AOP_LIT)
1226     return zero;
1227
1228   /* depending on type */
1229   switch (aop->type)
1230     {
1231     case AOP_DUMMY:
1232       return zero;
1233
1234     case AOP_R0:
1235     case AOP_R1:
1236       /* if we need to increment it */
1237       while (offset > aop->coff)
1238         {
1239           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1240           aop->coff++;
1241         }
1242
1243       while (offset < aop->coff)
1244         {
1245           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1246           aop->coff--;
1247         }
1248
1249       aop->coff = offset;
1250       if (aop->paged)
1251         {
1252           emitcode ("movx", "a,@%s", aop->aopu.aop_ptr->name);
1253           return (dname ? "acc" : "a");
1254         }
1255       SNPRINTF (buffer, sizeof(buffer), "@%s", aop->aopu.aop_ptr->name);
1256       return Safe_strdup(buffer);
1257
1258     case AOP_DPTRn:
1259         assert(offset <= 3);
1260         return dptrn[aop->aopu.dptr][offset];
1261
1262     case AOP_DPTR:
1263     case AOP_DPTR2:
1264
1265       if (aop->type == AOP_DPTR2)
1266         {
1267           genSetDPTR (1);
1268         }
1269
1270       if (saveAcc)
1271         {
1272             TR_AP("#1");
1273 //          if (aop->type != AOP_DPTR2)
1274 //          {
1275 //              if (saveAccWarn) { fprintf(stderr, "saveAcc for DPTR...\n"); }
1276 //              emitcode(";", "spanky: saveAcc for DPTR");
1277 //          }
1278
1279             emitcode ("xch", "a, %s", saveAcc);
1280         }
1281
1282       _flushLazyDPS ();
1283
1284       while (offset > aop->coff)
1285         {
1286           emitcode ("inc", "dptr");
1287           aop->coff++;
1288         }
1289
1290       while (offset < aop->coff)
1291         {
1292           emitcode ("lcall", "__decdptr");
1293           aop->coff--;
1294         }
1295
1296       aop->coff = offset;
1297       if (aop->code)
1298         {
1299           emitcode ("clr", "a");
1300           emitcode ("movc", "a,@a+dptr");
1301         }
1302       else
1303         {
1304           emitcode ("movx", "a,@dptr");
1305         }
1306
1307       if (aop->type == AOP_DPTR2)
1308         {
1309           genSetDPTR (0);
1310         }
1311
1312         if (saveAcc)
1313         {
1314        TR_AP("#2");
1315               emitcode ("xch", "a, %s", saveAcc);
1316 //            if (strcmp(saveAcc, "_ap"))
1317 //            {
1318 //                emitcode(";", "spiffy: non _ap return from aopGet.");
1319 //            }
1320
1321               return saveAcc;
1322         }
1323       return (dname ? "acc" : "a");
1324
1325     case AOP_IMMD:
1326       if (aop->aopu.aop_immd.from_cast_remat && (offset == (aop->size-1)))
1327       {
1328           SNPRINTF(buffer, sizeof(buffer),
1329                    "%s",aop->aopu.aop_immd.aop_immd2);
1330       }
1331       else if (bit16)
1332       {
1333          SNPRINTF(buffer, sizeof(buffer),
1334                   "#%s", aop->aopu.aop_immd.aop_immd1);
1335       }
1336       else if (offset)
1337       {
1338           switch (offset) {
1339           case 1:
1340               tsprintf(buffer, sizeof(buffer),
1341                        "#!his",aop->aopu.aop_immd.aop_immd1);
1342               break;
1343           case 2:
1344               tsprintf(buffer, sizeof(buffer),
1345                        "#!hihis",aop->aopu.aop_immd.aop_immd1);
1346               break;
1347           case 3:
1348               tsprintf(buffer, sizeof(buffer),
1349                        "#!hihihis",aop->aopu.aop_immd.aop_immd1);
1350               break;
1351           default: /* should not need this (just in case) */
1352               SNPRINTF (buffer, sizeof(buffer),
1353                         "#(%s >> %d)",
1354                        aop->aopu.aop_immd.aop_immd1,
1355                        offset * 8);
1356           }
1357       }
1358       else
1359       {
1360         SNPRINTF (buffer, sizeof(buffer),
1361                   "#%s", aop->aopu.aop_immd.aop_immd1);
1362       }
1363       return Safe_strdup(buffer);
1364
1365     case AOP_DIR:
1366       if (offset)
1367       {
1368         SNPRINTF (buffer, sizeof(buffer),
1369                   "(%s + %d)",
1370                  aop->aopu.aop_dir,
1371                  offset);
1372       }
1373       else
1374       {
1375         SNPRINTF(buffer, sizeof(buffer),
1376                  "%s", aop->aopu.aop_dir);
1377       }
1378
1379       return Safe_strdup(buffer);
1380
1381     case AOP_REG:
1382       if (dname)
1383         return aop->aopu.aop_reg[offset]->dname;
1384       else
1385         return aop->aopu.aop_reg[offset]->name;
1386
1387     case AOP_CRY:
1388       emitcode ("clr", "a");
1389       emitcode ("mov", "c,%s", aop->aopu.aop_dir);
1390       emitcode ("rlc", "a");
1391       return (dname ? "acc" : "a");
1392
1393     case AOP_ACC:
1394       if (!offset && dname)
1395         return "acc";
1396       return aop->aopu.aop_str[offset];
1397
1398     case AOP_LIT:
1399       return aopLiteral (aop->aopu.aop_lit, offset);
1400
1401     case AOP_STR:
1402       aop->coff = offset;
1403       if (strcmp (aop->aopu.aop_str[offset], "a") == 0 &&
1404           dname)
1405         return "acc";
1406
1407       return aop->aopu.aop_str[offset];
1408
1409     }
1410
1411   werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1412           "aopget got unsupported aop->type");
1413   exit (1);
1414
1415   return NULL;  // not reached, but makes compiler happy.
1416 }
1417 /*-----------------------------------------------------------------*/
1418 /* aopPut - puts a string for a aop                                */
1419 /*-----------------------------------------------------------------*/
1420 static void
1421 aopPut (asmop * aop, char *s, int offset)
1422 {
1423   if (aop->size && offset > (aop->size - 1))
1424     {
1425       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1426               "aopPut got offset > aop->size");
1427       exit (1);
1428     }
1429
1430   /* will assign value to value */
1431   /* depending on where it is ofcourse */
1432   switch (aop->type)
1433     {
1434     case AOP_DUMMY:
1435       MOVA (s);         /* read s in case it was volatile */
1436       break;
1437
1438     case AOP_DIR:
1439         if (offset)
1440         {
1441             SNPRINTF (buffer, sizeof(buffer),
1442                       "(%s + %d)",
1443                       aop->aopu.aop_dir, offset);
1444         }
1445         else
1446         {
1447             SNPRINTF (buffer, sizeof(buffer),
1448                      "%s", aop->aopu.aop_dir);
1449         }
1450
1451
1452         if (strcmp (buffer, s))
1453         {
1454             emitcode ("mov", "%s,%s", buffer, s);
1455         }
1456       break;
1457
1458     case AOP_REG:
1459       if (strcmp (aop->aopu.aop_reg[offset]->name, s) != 0 &&
1460           strcmp (aop->aopu.aop_reg[offset]->dname, s) != 0)
1461         {
1462           if (*s == '@' ||
1463               strcmp (s, "r0") == 0 ||
1464               strcmp (s, "r1") == 0 ||
1465               strcmp (s, "r2") == 0 ||
1466               strcmp (s, "r3") == 0 ||
1467               strcmp (s, "r4") == 0 ||
1468               strcmp (s, "r5") == 0 ||
1469               strcmp (s, "r6") == 0 ||
1470               strcmp (s, "r7") == 0)
1471             {
1472                 emitcode ("mov", "%s,%s",
1473                           aop->aopu.aop_reg[offset]->dname, s);
1474             }
1475             else
1476             {
1477                 emitcode ("mov", "%s,%s",
1478                           aop->aopu.aop_reg[offset]->name, s);
1479             }
1480         }
1481       break;
1482
1483     case AOP_DPTRn:
1484         emitcode ("mov","%s,%s",dptrn[aop->aopu.dptr][offset],s);
1485         break;
1486
1487     case AOP_DPTR:
1488     case AOP_DPTR2:
1489
1490       if (aop->type == AOP_DPTR2)
1491         {
1492           genSetDPTR (1);
1493         }
1494       _flushLazyDPS ();
1495
1496       if (aop->code)
1497         {
1498           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1499                   "aopPut writting to code space");
1500           exit (1);
1501         }
1502
1503       while (offset > aop->coff)
1504         {
1505           aop->coff++;
1506           emitcode ("inc", "dptr");
1507         }
1508
1509       while (offset < aop->coff)
1510         {
1511           aop->coff--;
1512           emitcode ("lcall", "__decdptr");
1513         }
1514
1515       aop->coff = offset;
1516
1517       /* if not in accumulater */
1518       MOVA (s);
1519
1520       emitcode ("movx", "@dptr,a");
1521
1522       if (aop->type == AOP_DPTR2)
1523         {
1524           genSetDPTR (0);
1525         }
1526       break;
1527
1528     case AOP_R0:
1529     case AOP_R1:
1530       while (offset > aop->coff)
1531         {
1532           aop->coff++;
1533           emitcode ("inc", "%s", aop->aopu.aop_ptr->name);
1534         }
1535       while (offset < aop->coff)
1536         {
1537           aop->coff--;
1538           emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1539         }
1540       aop->coff = offset;
1541
1542       if (aop->paged)
1543         {
1544           MOVA (s);
1545           emitcode ("movx", "@%s,a", aop->aopu.aop_ptr->name);
1546
1547         }
1548       else if (*s == '@')
1549         {
1550           MOVA (s);
1551           emitcode ("mov", "@%s,a", aop->aopu.aop_ptr->name);
1552         }
1553       else if (strcmp (s, "r0") == 0 ||
1554                strcmp (s, "r1") == 0 ||
1555                strcmp (s, "r2") == 0 ||
1556                strcmp (s, "r3") == 0 ||
1557                strcmp (s, "r4") == 0 ||
1558                strcmp (s, "r5") == 0 ||
1559                strcmp (s, "r6") == 0 ||
1560                strcmp (s, "r7") == 0)
1561         {
1562           char buff[10];
1563           SNPRINTF(buff, sizeof(buff),
1564                    "a%s", s);
1565           emitcode ("mov", "@%s,%s",
1566                     aop->aopu.aop_ptr->name, buff);
1567         }
1568         else
1569         {
1570             emitcode ("mov", "@%s,%s", aop->aopu.aop_ptr->name, s);
1571         }
1572       break;
1573
1574     case AOP_STK:
1575       if (strcmp (s, "a") == 0)
1576         emitcode ("push", "acc");
1577       else
1578         if (*s=='@') {
1579           MOVA(s);
1580           emitcode ("push", "acc");
1581         } else {
1582           emitcode ("push", s);
1583         }
1584
1585       break;
1586
1587     case AOP_CRY:
1588       /* if bit variable */
1589       if (!aop->aopu.aop_dir)
1590         {
1591           emitcode ("clr", "a");
1592           emitcode ("rlc", "a");
1593         }
1594       else
1595         {
1596           if (s == zero)
1597             emitcode ("clr", "%s", aop->aopu.aop_dir);
1598           else if (s == one)
1599             emitcode ("setb", "%s", aop->aopu.aop_dir);
1600           else if (!strcmp (s, "c"))
1601             emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1602           else
1603             {
1604               if (strcmp (s, "a"))
1605                 {
1606                   MOVA (s);
1607                 }
1608               {
1609                 /* set C, if a >= 1 */
1610                 emitcode ("add", "a,#!constbyte",0xff);
1611                 emitcode ("mov", "%s,c", aop->aopu.aop_dir);
1612               }
1613             }
1614         }
1615       break;
1616
1617     case AOP_STR:
1618       aop->coff = offset;
1619       if (strcmp (aop->aopu.aop_str[offset], s))
1620         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1621       break;
1622
1623     case AOP_ACC:
1624       aop->coff = offset;
1625       if (!offset && (strcmp (s, "acc") == 0))
1626         break;
1627
1628       if (strcmp (aop->aopu.aop_str[offset], s))
1629         emitcode ("mov", "%s,%s", aop->aopu.aop_str[offset], s);
1630       break;
1631
1632     default:
1633       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1634               "aopPut got unsupported aop->type");
1635       exit (1);
1636     }
1637
1638 }
1639
1640
1641 /*--------------------------------------------------------------------*/
1642 /* reAdjustPreg - points a register back to where it should (coff==0) */
1643 /*--------------------------------------------------------------------*/
1644 static void
1645 reAdjustPreg (asmop * aop)
1646 {
1647   if ((aop->coff==0) || (aop->size <= 1)) {
1648     return;
1649   }
1650
1651   switch (aop->type)
1652     {
1653     case AOP_R0:
1654     case AOP_R1:
1655       while (aop->coff--)
1656         emitcode ("dec", "%s", aop->aopu.aop_ptr->name);
1657       break;
1658     case AOP_DPTR:
1659     case AOP_DPTR2:
1660       if (aop->type == AOP_DPTR2)
1661         {
1662           genSetDPTR (1);
1663           _flushLazyDPS ();
1664         }
1665       while (aop->coff--)
1666         {
1667           emitcode ("lcall", "__decdptr");
1668         }
1669
1670       if (aop->type == AOP_DPTR2)
1671         {
1672           genSetDPTR (0);
1673         }
1674       break;
1675
1676     }
1677   aop->coff=0;
1678 }
1679
1680 #define AOP(op) op->aop
1681 #define AOP_TYPE(op) AOP(op)->type
1682 #define AOP_SIZE(op) AOP(op)->size
1683 #define IS_AOP_PREG(x) (AOP(x) && (AOP_TYPE(x) == AOP_R1 || \
1684                        AOP_TYPE(x) == AOP_R0))
1685
1686 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY ||  \
1687                         AOP_TYPE(x) == AOP_DPTR || AOP_TYPE(x) == AOP_DPTR2 || \
1688                          AOP(x)->paged))
1689
1690 #define AOP_INPREG(x) (x && (x->type == AOP_REG &&                        \
1691                       (x->aopu.aop_reg[0] == ds390_regWithIdx(R0_IDX) || \
1692                       x->aopu.aop_reg[0] == ds390_regWithIdx(R1_IDX) )))
1693 #define AOP_INDPTRn(x) (AOP_TYPE(x) == AOP_DPTRn)
1694 #define AOP_USESDPTR(x) ((AOP_TYPE(x) == AOP_DPTR) || (AOP_TYPE(x) == AOP_STR))
1695 #define AOP_USESDPTR2(x) ((AOP_TYPE(x) == AOP_DPTR2) || (AOP_TYPE(x) == AOP_DPTRn))
1696
1697 // The following two macros can be used even if the aop has not yet been aopOp'd.
1698 #define AOP_IS_STR(x) (IS_SYMOP(x) && OP_SYMBOL(x)->ruonly)
1699 #define AOP_IS_DPTRn(x) (IS_SYMOP(x) && OP_SYMBOL(x)->dptr)
1700
1701 /* Workaround for DS80C390 bug: div ab may return bogus results
1702  * if A is accessed in instruction immediately before the div.
1703  *
1704  * Will be fixed in B4 rev of processor, Dallas claims.
1705  */
1706
1707 #define LOAD_AB_FOR_DIV(LEFT, RIGHT, L)       \
1708     if (!AOP_NEEDSACC(RIGHT))         \
1709     {               \
1710       /* We can load A first, then B, since     \
1711        * B (the RIGHT operand) won't clobber A,   \
1712        * thus avoiding touching A right before the div. \
1713        */             \
1714       D(emitcode(";", "DS80C390 div bug: rearranged ops.");); \
1715       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);     \
1716       MOVA(L);            \
1717       L = aopGet(AOP(RIGHT),0,FALSE,FALSE,"b"); \
1718       MOVB(L); \
1719     }               \
1720     else              \
1721     {               \
1722       /* Just stuff in a nop after loading A. */    \
1723       emitcode("mov","b,%s",aopGet(AOP(RIGHT),0,FALSE,FALSE,NULL));\
1724       L = aopGet(AOP(LEFT),0,FALSE,FALSE,NULL);   \
1725       MOVA(L);            \
1726       emitcode("nop", "; workaround for DS80C390 div bug.");  \
1727     }
1728
1729
1730 /*-----------------------------------------------------------------*/
1731 /* opIsGptr: returns non-zero if the passed operand is       */
1732 /* a generic pointer type.             */
1733 /*-----------------------------------------------------------------*/
1734 static int
1735 opIsGptr (operand * op)
1736 {
1737   sym_link *type = operandType (op);
1738
1739   if ((AOP_SIZE (op) == GPTRSIZE) && IS_GENPTR (type))
1740     {
1741       return 1;
1742     }
1743   return 0;
1744 }
1745
1746 /*-----------------------------------------------------------------*/
1747 /* getDataSize - get the operand data size                         */
1748 /*-----------------------------------------------------------------*/
1749 static int
1750 getDataSize (operand * op)
1751 {
1752   int size;
1753   size = AOP_SIZE (op);
1754   if (size == GPTRSIZE)
1755     {
1756       sym_link *type = operandType (op);
1757       if (IS_GENPTR (type))
1758         {
1759           /* generic pointer; arithmetic operations
1760            * should ignore the high byte (pointer type).
1761            */
1762           size--;
1763         }
1764     }
1765   return size;
1766 }
1767
1768 /*-----------------------------------------------------------------*/
1769 /* outAcc - output Acc                                             */
1770 /*-----------------------------------------------------------------*/
1771 static void
1772 outAcc (operand * result)
1773 {
1774   int size, offset;
1775   size = getDataSize (result);
1776   if (size)
1777     {
1778       aopPut (AOP (result), "a", 0);
1779       size--;
1780       offset = 1;
1781       /* unsigned or positive */
1782       while (size--)
1783         {
1784           aopPut (AOP (result), zero, offset++);
1785         }
1786     }
1787 }
1788
1789 /*-----------------------------------------------------------------*/
1790 /* outBitC - output a bit C                                        */
1791 /*-----------------------------------------------------------------*/
1792 static void
1793 outBitC (operand * result)
1794 {
1795   /* if the result is bit */
1796   if (AOP_TYPE (result) == AOP_CRY)
1797     {
1798       aopPut (AOP (result), "c", 0);
1799     }
1800   else
1801     {
1802       emitcode ("clr", "a");
1803       emitcode ("rlc", "a");
1804       outAcc (result);
1805     }
1806 }
1807
1808 /*-----------------------------------------------------------------*/
1809 /* toBoolean - emit code for orl a,operator(sizeop)                */
1810 /*-----------------------------------------------------------------*/
1811 static void
1812 toBoolean (operand * oper)
1813 {
1814   int   size = AOP_SIZE (oper) - 1;
1815   int   offset = 1;
1816   bool usedB = FALSE;
1817
1818   /* The generic part of a generic pointer should
1819    * not participate in it's truth value.
1820    *
1821    * i.e. 0x10000000 is zero.
1822    */
1823   if (opIsGptr (oper))
1824     {
1825       D (emitcode (";", "toBoolean: generic ptr special case."););
1826       size--;
1827     }
1828
1829   _startLazyDPSEvaluation ();
1830   if (AOP_NEEDSACC (oper) && size)
1831     {
1832       usedB = TRUE;
1833       if (_G.bInUse)
1834       {
1835           emitcode ("push", "b");
1836       }
1837       MOVB (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1838     }
1839   else
1840     {
1841       MOVA (aopGet (AOP (oper), 0, FALSE, FALSE, NULL));
1842     }
1843
1844   while (size--)
1845     {
1846       if (usedB)
1847         {
1848           emitcode ("orl", "b,%s",
1849                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1850         }
1851       else
1852         {
1853           emitcode ("orl", "a,%s",
1854                     aopGet (AOP (oper), offset++, FALSE, FALSE, NULL));
1855         }
1856     }
1857   _endLazyDPSEvaluation ();
1858
1859   if (usedB)
1860     {
1861       emitcode ("mov", "a,b");
1862       if (_G.bInUse)
1863       {
1864           emitcode ("pop", "b");
1865       }
1866
1867     }
1868 }
1869
1870
1871 /*-----------------------------------------------------------------*/
1872 /* genNot - generate code for ! operation                          */
1873 /*-----------------------------------------------------------------*/
1874 static void
1875 genNot (iCode * ic)
1876 {
1877   symbol *tlbl;
1878
1879   D (emitcode (";", "genNot "););
1880
1881   /* assign asmOps to operand & result */
1882   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1883   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1884
1885   /* if in bit space then a special case */
1886   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1887     {
1888       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1889       emitcode ("cpl", "c");
1890       outBitC (IC_RESULT (ic));
1891       goto release;
1892     }
1893
1894   toBoolean (IC_LEFT (ic));
1895
1896   tlbl = newiTempLabel (NULL);
1897   emitcode ("cjne", "a,#1,!tlabel", tlbl->key + 100);
1898   emitcode ("", "!tlabeldef", tlbl->key + 100);
1899   outBitC (IC_RESULT (ic));
1900
1901 release:
1902   /* release the aops */
1903   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1904   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1905 }
1906
1907
1908 /*-----------------------------------------------------------------*/
1909 /* genCpl - generate code for complement                           */
1910 /*-----------------------------------------------------------------*/
1911 static void
1912 genCpl (iCode * ic)
1913 {
1914   int offset = 0;
1915   int size;
1916   symbol *tlbl;
1917
1918   D (emitcode (";", "genCpl "););
1919
1920
1921   /* assign asmOps to operand & result */
1922   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1923   aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR(IC_LEFT (ic)));
1924
1925   /* special case if in bit space */
1926   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY) {
1927     if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY) {
1928       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
1929       emitcode ("cpl", "c");
1930       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
1931       goto release;
1932     }
1933     tlbl=newiTempLabel(NULL);
1934     emitcode ("cjne", "%s,#0x01,%05d$",
1935               aopGet(AOP(IC_LEFT(ic)), 0, FALSE,FALSE,NULL), tlbl->key+100);
1936     emitcode ("", "%05d$:", tlbl->key+100);
1937     outBitC (IC_RESULT(ic));
1938     goto release;
1939   }
1940
1941   size = AOP_SIZE (IC_RESULT (ic));
1942   _startLazyDPSEvaluation ();
1943   while (size--)
1944     {
1945       MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
1946       emitcode ("cpl", "a");
1947       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1948     }
1949   _endLazyDPSEvaluation ();
1950
1951
1952 release:
1953   /* release the aops */
1954   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
1955   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
1956 }
1957
1958 /*-----------------------------------------------------------------*/
1959 /* genUminusFloat - unary minus for floating points                */
1960 /*-----------------------------------------------------------------*/
1961 static void
1962 genUminusFloat (operand * op, operand * result)
1963 {
1964   int size, offset = 0;
1965
1966   D(emitcode (";", "genUminusFloat"););
1967
1968   /* for this we just copy and then flip the bit */
1969
1970   _startLazyDPSEvaluation ();
1971   size = AOP_SIZE (op) - 1;
1972
1973   while (size--)
1974   {
1975       aopPut (AOP (result),
1976               aopGet (AOP (op), offset, FALSE, FALSE, NULL),
1977               offset);
1978       offset++;
1979     }
1980
1981   MOVA(aopGet (AOP (op), offset, FALSE, FALSE, NULL));
1982
1983   emitcode ("cpl", "acc.7");
1984   aopPut (AOP (result), "a", offset);
1985   _endLazyDPSEvaluation ();
1986 }
1987
1988 /*-----------------------------------------------------------------*/
1989 /* genUminus - unary minus code generation                         */
1990 /*-----------------------------------------------------------------*/
1991 static void
1992 genUminus (iCode * ic)
1993 {
1994   int offset, size;
1995   sym_link *optype;
1996
1997   D (emitcode (";", "genUminus "););
1998
1999   /* assign asmops */
2000   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2001   aopOp (IC_RESULT (ic), ic, TRUE, (AOP_TYPE(IC_LEFT (ic)) == AOP_DPTR));
2002
2003   /* if both in bit space then special
2004      case */
2005   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2006       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2007     {
2008
2009       emitcode ("mov", "c,%s", IC_LEFT (ic)->aop->aopu.aop_dir);
2010       emitcode ("cpl", "c");
2011       emitcode ("mov", "%s,c", IC_RESULT (ic)->aop->aopu.aop_dir);
2012       goto release;
2013     }
2014
2015   optype = operandType (IC_LEFT (ic));
2016
2017   /* if float then do float stuff */
2018   if (IS_FLOAT (optype))
2019     {
2020       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2021       goto release;
2022     }
2023
2024   /* otherwise subtract from zero */
2025   size = AOP_SIZE (IC_LEFT (ic));
2026   offset = 0;
2027   _startLazyDPSEvaluation ();
2028   while (size--)
2029     {
2030       char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL);
2031       if (!strcmp (l, "a"))
2032         {
2033           if (offset == 0)
2034             SETC;
2035           emitcode ("cpl", "a");
2036           emitcode ("addc", "a,#0");
2037         }
2038       else
2039         {
2040           if (offset == 0)
2041             CLRC;
2042           emitcode ("clr", "a");
2043           emitcode ("subb", "a,%s", l);
2044         }
2045       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2046     }
2047   _endLazyDPSEvaluation ();
2048
2049   /* if any remaining bytes in the result */
2050   /* we just need to propagate the sign   */
2051   if ((size = (AOP_SIZE(IC_RESULT(ic)) - AOP_SIZE(IC_LEFT(ic)))) != 0)
2052     {
2053       emitcode ("rlc", "a");
2054       emitcode ("subb", "a,acc");
2055       while (size--)
2056         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2057     }
2058
2059 release:
2060   /* release the aops */
2061   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? 0 : 1));
2062   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2063 }
2064
2065 /*-----------------------------------------------------------------*/
2066 /* savermask - saves registers in the mask                         */
2067 /*-----------------------------------------------------------------*/
2068 static void savermask(bitVect *rs_mask)
2069 {
2070     int i;
2071     if (options.useXstack) {
2072         if (bitVectBitValue (rs_mask, R0_IDX))
2073             emitcode ("mov", "b,r0");
2074         emitcode ("mov", "r0,%s", spname);
2075         for (i = 0; i < ds390_nRegs; i++) {
2076             if (bitVectBitValue (rs_mask, i)) {
2077                 if (i == R0_IDX)
2078                     emitcode ("mov", "a,b");
2079                 else
2080                     emitcode ("mov", "a,%s", ds390_regWithIdx (i)->name);
2081                 emitcode ("movx", "@r0,a");
2082                 emitcode ("inc", "r0");
2083             }
2084         }
2085         emitcode ("mov", "%s,r0", spname);
2086         if (bitVectBitValue (rs_mask, R0_IDX))
2087             emitcode ("mov", "r0,b");
2088     } else {
2089         for (i = 0; i < ds390_nRegs; i++) {
2090             if (bitVectBitValue (rs_mask, i))
2091                 emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
2092         }
2093     }
2094 }
2095
2096 /*-----------------------------------------------------------------*/
2097 /* saveRegisters - will look for a call and save the registers     */
2098 /*-----------------------------------------------------------------*/
2099 static void
2100 saveRegisters (iCode * lic)
2101 {
2102   iCode *ic;
2103   bitVect *rsave;
2104
2105   /* look for call */
2106   for (ic = lic; ic; ic = ic->next)
2107     if (ic->op == CALL || ic->op == PCALL)
2108       break;
2109
2110   if (!ic)
2111     {
2112       fprintf (stderr, "found parameter push with no function call\n");
2113       return;
2114     }
2115
2116   /* if the registers have been saved already then
2117      do nothing */
2118   if (ic->regsSaved
2119       || (IS_SYMOP(IC_LEFT(ic)) && IFFUNC_ISNAKED(OP_SYM_TYPE(IC_LEFT(ic))) && !TARGET_IS_DS400) )
2120     return ;
2121
2122   /* special case if DPTR alive across a function call then must save it
2123      even though callee saves */
2124   if (IS_SYMOP(IC_LEFT(ic)) &&
2125       IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2126       int i;
2127       rsave = newBitVect(ic->rMask->size);
2128       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2129           if (bitVectBitValue(ic->rMask,i))
2130               rsave = bitVectSetBit(rsave,i);
2131       }
2132       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2133   } else {
2134     /* safe the registers in use at this time but skip the
2135        ones for the result */
2136     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2137                            ds390_rUmaskForOp (IC_RESULT(ic)));
2138   }
2139   ic->regsSaved = 1;
2140   savermask(rsave);
2141 }
2142
2143 /*-----------------------------------------------------------------*/
2144 /* usavermask - restore registers with mask                        */
2145 /*-----------------------------------------------------------------*/
2146 static void unsavermask(bitVect *rs_mask)
2147 {
2148     int i;
2149     if (options.useXstack) {
2150         emitcode ("mov", "r0,%s", spname);
2151         for (i = ds390_nRegs; i >= 0; i--) {
2152             if (bitVectBitValue (rs_mask, i)) {
2153                 emitcode ("dec", "r0");
2154                 emitcode ("movx", "a,@r0");
2155                 if (i == R0_IDX)
2156                     emitcode ("mov", "b,a");
2157                 else
2158                     emitcode ("mov", "%s,a", ds390_regWithIdx (i)->name);
2159             }
2160         }
2161         emitcode ("mov", "%s,r0", spname);
2162         if (bitVectBitValue (rs_mask, R0_IDX))
2163             emitcode ("mov", "r0,b");
2164     } else {
2165         for (i = ds390_nRegs; i >= 0; i--) {
2166             if (bitVectBitValue (rs_mask, i))
2167                 emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
2168         }
2169     }
2170 }
2171
2172 /*-----------------------------------------------------------------*/
2173 /* unsaveRegisters - pop the pushed registers                      */
2174 /*-----------------------------------------------------------------*/
2175 static void
2176 unsaveRegisters (iCode * ic)
2177 {
2178   bitVect *rsave;
2179
2180   if (IFFUNC_CALLEESAVES(OP_SYMBOL (IC_LEFT (ic))->type)) {
2181       int i;
2182       rsave = newBitVect(ic->rMask->size);
2183       for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
2184           if (bitVectBitValue(ic->rMask,i))
2185               rsave = bitVectSetBit(rsave,i);
2186       }
2187       rsave = bitVectCplAnd(rsave,ds390_rUmaskForOp (IC_RESULT(ic)));
2188   } else {
2189     /* restore the registers in use at this time but skip the
2190        ones for the result */
2191     rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
2192                            ds390_rUmaskForOp (IC_RESULT(ic)));
2193   }
2194   unsavermask(rsave);
2195 }
2196
2197
2198 /*-----------------------------------------------------------------*/
2199 /* pushSide -                */
2200 /*-----------------------------------------------------------------*/
2201 static void
2202 pushSide (operand * oper, int size)
2203 {
2204   int offset = 0;
2205   _startLazyDPSEvaluation ();
2206   while (size--)
2207     {
2208       char *l = aopGet (AOP (oper), offset++, FALSE, TRUE, NULL);
2209       if (AOP_TYPE (oper) != AOP_REG &&
2210           AOP_TYPE (oper) != AOP_DIR &&
2211           strcmp (l, "a"))
2212         {
2213           emitcode ("mov", "a,%s", l);
2214           emitcode ("push", "acc");
2215         }
2216       else
2217         emitcode ("push", "%s", l);
2218     }
2219   _endLazyDPSEvaluation ();
2220 }
2221
2222 /*-----------------------------------------------------------------*/
2223 /* assignResultValue -               */
2224 /*-----------------------------------------------------------------*/
2225 static void
2226 assignResultValue (operand * oper)
2227 {
2228   int offset = 0;
2229   int size = AOP_SIZE (oper);
2230   bool pushedAcc = FALSE;
2231
2232   if (size == fReturnSizeDS390)
2233   {
2234       /* I don't think this case can ever happen... */
2235       /* ACC is the last part of this. If writing the result
2236        * uses AC, we must preserve it.
2237        */
2238       if (AOP_NEEDSACC(oper))
2239       {
2240           emitcode(";", "assignResultValue special case for ACC.");
2241           emitcode("push", "acc");
2242           pushedAcc = TRUE;
2243           size--;
2244       }
2245   }
2246
2247
2248   _startLazyDPSEvaluation ();
2249   while (size--)
2250     {
2251       aopPut (AOP (oper), fReturn[offset], offset);
2252       offset++;
2253     }
2254   _endLazyDPSEvaluation ();
2255
2256   if (pushedAcc)
2257     {
2258         emitcode("pop", "acc");
2259         aopPut(AOP(oper), "a", offset);
2260     }
2261 }
2262
2263
2264 /*-----------------------------------------------------------------*/
2265 /* genXpush - pushes onto the external stack                       */
2266 /*-----------------------------------------------------------------*/
2267 static void
2268 genXpush (iCode * ic)
2269 {
2270   asmop *aop = newAsmop (0);
2271   regs *r;
2272   int size, offset = 0;
2273
2274   D (emitcode (";", "genXpush ");
2275     );
2276
2277   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2278   r = getFreePtr (ic, &aop, FALSE);
2279
2280
2281   emitcode ("mov", "%s,_spx", r->name);
2282
2283   size = AOP_SIZE (IC_LEFT (ic));
2284   _startLazyDPSEvaluation ();
2285   while (size--)
2286     {
2287
2288       MOVA (aopGet (AOP (IC_LEFT (ic)),
2289                         offset++, FALSE, FALSE, NULL));
2290       emitcode ("movx", "@%s,a", r->name);
2291       emitcode ("inc", "%s", r->name);
2292
2293     }
2294   _endLazyDPSEvaluation ();
2295
2296
2297   emitcode ("mov", "_spx,%s", r->name);
2298
2299   freeAsmop (NULL, aop, ic, TRUE);
2300   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2301 }
2302
2303 /*-----------------------------------------------------------------*/
2304 /* genIpush - generate code for pushing this gets a little complex  */
2305 /*-----------------------------------------------------------------*/
2306 static void
2307 genIpush (iCode * ic)
2308 {
2309   int size, offset = 0;
2310   char *l;
2311
2312   D (emitcode (";", "genIpush ");
2313     );
2314
2315   /* if this is not a parm push : ie. it is spill push
2316      and spill push is always done on the local stack */
2317   if (!ic->parmPush)
2318     {
2319
2320       /* and the item is spilt then do nothing */
2321       if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL(IC_LEFT(ic))->dptr)
2322         return;
2323
2324       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2325       size = AOP_SIZE (IC_LEFT (ic));
2326       /* push it on the stack */
2327       _startLazyDPSEvaluation ();
2328       while (size--)
2329         {
2330           l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2331           if (*l == '#')
2332             {
2333               MOVA (l);
2334               l = "acc";
2335             }
2336           emitcode ("push", "%s", l);
2337         }
2338       _endLazyDPSEvaluation ();
2339       return;
2340     }
2341
2342   /* this is a paramter push: in this case we call
2343      the routine to find the call and save those
2344      registers that need to be saved */
2345   saveRegisters (ic);
2346
2347   /* if use external stack then call the external
2348      stack pushing routine */
2349   if (options.useXstack)
2350     {
2351       genXpush (ic);
2352       return;
2353     }
2354
2355   /* then do the push */
2356   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2357
2358   // pushSide(IC_LEFT(ic), AOP_SIZE(IC_LEFT(ic)));
2359   size = AOP_SIZE (IC_LEFT (ic));
2360
2361   _startLazyDPSEvaluation ();
2362   while (size--)
2363     {
2364       l = aopGet (AOP (IC_LEFT (ic)), offset++, FALSE, TRUE, NULL);
2365       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG &&
2366           AOP_TYPE (IC_LEFT (ic)) != AOP_DIR &&
2367           strcmp (l, "acc"))
2368         {
2369           emitcode ("mov", "a,%s", l);
2370           emitcode ("push", "acc");
2371         }
2372       else
2373         {
2374             emitcode ("push", "%s", l);
2375         }
2376     }
2377   _endLazyDPSEvaluation ();
2378
2379   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2380 }
2381
2382 /*-----------------------------------------------------------------*/
2383 /* genIpop - recover the registers: can happen only for spilling   */
2384 /*-----------------------------------------------------------------*/
2385 static void
2386 genIpop (iCode * ic)
2387 {
2388   int size, offset;
2389
2390   D (emitcode (";", "genIpop ");
2391     );
2392
2393
2394   /* if the temp was not pushed then */
2395   if (OP_SYMBOL (IC_LEFT (ic))->isspilt || OP_SYMBOL (IC_LEFT (ic))->dptr)
2396     return;
2397
2398   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2399   size = AOP_SIZE (IC_LEFT (ic));
2400   offset = (size - 1);
2401   _startLazyDPSEvaluation ();
2402   while (size--)
2403     {
2404       emitcode ("pop", "%s", aopGet (AOP (IC_LEFT (ic)), offset--,
2405                                      FALSE, TRUE, NULL));
2406     }
2407   _endLazyDPSEvaluation ();
2408
2409   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2410 }
2411
2412 /*-----------------------------------------------------------------*/
2413 /* unsaveRBank - restores the resgister bank from stack            */
2414 /*-----------------------------------------------------------------*/
2415 static void
2416 unsaveRBank (int bank, iCode * ic, bool popPsw)
2417 {
2418   int i;
2419   asmop *aop = NULL;
2420   regs *r = NULL;
2421
2422   if (options.useXstack)
2423   {
2424       if (!ic)
2425       {
2426           /* Assume r0 is available for use. */
2427           r = ds390_regWithIdx (R0_IDX);;
2428       }
2429       else
2430       {
2431           aop = newAsmop (0);
2432           r = getFreePtr (ic, &aop, FALSE);
2433       }
2434       emitcode ("mov", "%s,_spx", r->name);
2435   }
2436
2437   if (popPsw)
2438     {
2439       if (options.useXstack)
2440       {
2441           emitcode ("movx", "a,@%s", r->name);
2442           emitcode ("mov", "psw,a");
2443           emitcode ("dec", "%s", r->name);
2444         }
2445       else
2446       {
2447         emitcode ("pop", "psw");
2448       }
2449     }
2450
2451   for (i = 7; i >= 0; i--) /* only R7-R0 needs to be popped */
2452     {
2453       if (options.useXstack)
2454         {
2455           emitcode ("movx", "a,@%s", r->name);
2456           emitcode ("mov", "(%s+%d),a",
2457                     regs390[i].base, 8 * bank + regs390[i].offset);
2458           emitcode ("dec", "%s", r->name);
2459
2460         }
2461       else
2462         emitcode ("pop", "(%s+%d)",
2463                   regs390[i].base, 8 * bank + regs390[i].offset);
2464     }
2465
2466   if (options.useXstack)
2467     {
2468       emitcode ("mov", "_spx,%s", r->name);
2469     }
2470
2471   if (aop)
2472   {
2473       freeAsmop (NULL, aop, ic, TRUE);
2474   }
2475 }
2476
2477 /*-----------------------------------------------------------------*/
2478 /* saveRBank - saves an entire register bank on the stack          */
2479 /*-----------------------------------------------------------------*/
2480 static void
2481 saveRBank (int bank, iCode * ic, bool pushPsw)
2482 {
2483   int i;
2484   asmop *aop = NULL;
2485   regs *r = NULL;
2486
2487   if (options.useXstack)
2488     {
2489         if (!ic)
2490         {
2491           /* Assume r0 is available for use. */
2492                   r = ds390_regWithIdx (R0_IDX);;
2493         }
2494         else
2495         {
2496           aop = newAsmop (0);
2497           r = getFreePtr (ic, &aop, FALSE);
2498         }
2499         emitcode ("mov", "%s,_spx", r->name);
2500     }
2501
2502   for (i = 0; i < 8 ; i++) /* only R0-R7 needs saving */
2503     {
2504       if (options.useXstack)
2505         {
2506           emitcode ("inc", "%s", r->name);
2507           emitcode ("mov", "a,(%s+%d)",
2508                     regs390[i].base, 8 * bank + regs390[i].offset);
2509           emitcode ("movx", "@%s,a", r->name);
2510         }
2511       else
2512         emitcode ("push", "(%s+%d)",
2513                   regs390[i].base, 8 * bank + regs390[i].offset);
2514     }
2515
2516   if (pushPsw)
2517     {
2518       if (options.useXstack)
2519         {
2520           emitcode ("mov", "a,psw");
2521           emitcode ("movx", "@%s,a", r->name);
2522           emitcode ("inc", "%s", r->name);
2523           emitcode ("mov", "_spx,%s", r->name);
2524         }
2525       else
2526       {
2527         emitcode ("push", "psw");
2528       }
2529
2530       emitcode ("mov", "psw,#!constbyte", (bank << 3) & 0x00ff);
2531     }
2532
2533   if (aop)
2534   {
2535     freeAsmop (NULL, aop, ic, TRUE);
2536   }
2537
2538   if (ic)
2539   {
2540     ic->bankSaved = 1;
2541   }
2542 }
2543
2544 /*-----------------------------------------------------------------*/
2545 /* genSend - gen code for SEND                                     */
2546 /*-----------------------------------------------------------------*/
2547 static void genSend(set *sendSet)
2548 {
2549     iCode *sic;
2550     int sendCount = 0 ;
2551     static int rb1_count = 0;
2552
2553     for (sic = setFirstItem (sendSet); sic;
2554          sic = setNextItem (sendSet)) {
2555         int size, offset = 0;
2556
2557         size=getSize(operandType(IC_LEFT(sic)));
2558         D (emitcode (";", "genSend argreg = %d, size = %d ",sic->argreg,size));
2559         if (sendCount == 0) { /* first parameter */
2560             // we know that dpl(hxb) is the result, so
2561             rb1_count = 0 ;
2562             _startLazyDPSEvaluation ();
2563             if (size>1) {
2564                 aopOp (IC_LEFT (sic), sic, FALSE,
2565                        (AOP_IS_STR(IC_LEFT(sic)) ? FALSE : TRUE));
2566             } else {
2567                 aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2568             }
2569             while (size--) {
2570                 char *l = aopGet (AOP (IC_LEFT (sic)), offset,
2571                                   FALSE, FALSE, NULL);
2572                 if (strcmp (l, fReturn[offset])) {
2573                     emitcode ("mov", "%s,%s",
2574                               fReturn[offset],
2575                               l);
2576                 }
2577                 offset++;
2578             }
2579             _endLazyDPSEvaluation ();
2580             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2581             rb1_count =0;
2582         } else { /* if more parameter in registers */
2583             aopOp (IC_LEFT (sic), sic, FALSE, TRUE);
2584             while (size--) {
2585                 emitcode ("mov","b1_%d,%s",rb1_count++,aopGet (AOP (IC_LEFT (sic)), offset++,
2586                                                                 FALSE, FALSE, NULL));
2587             }
2588             freeAsmop (IC_LEFT (sic), NULL, sic, TRUE);
2589         }
2590         sendCount++;
2591     }
2592 }
2593
2594 static void
2595 adjustEsp(const char *reg)
2596 {
2597     emitcode ("anl","%s,#3", reg);
2598     if (TARGET_IS_DS400)
2599     {
2600         emitcode ("orl","%s,#!constbyte",
2601                   reg,
2602                   (options.stack_loc >> 8) & 0xff);
2603     }
2604 }
2605
2606 /*-----------------------------------------------------------------*/
2607 /* genCall - generates a call statement                            */
2608 /*-----------------------------------------------------------------*/
2609 static void
2610 genCall (iCode * ic)
2611 {
2612   sym_link *dtype;
2613   bool restoreBank = FALSE;
2614   bool swapBanks = FALSE;
2615
2616   D (emitcode (";", "genCall "););
2617
2618   /* if we are calling a not _naked function that is not using
2619      the same register bank then we need to save the
2620      destination registers on the stack */
2621   dtype = operandType (IC_LEFT (ic));
2622   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
2623       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype)) &&
2624       IFFUNC_ISISR (currFunc->type))
2625   {
2626       if (!ic->bankSaved)
2627       {
2628            /* This is unexpected; the bank should have been saved in
2629             * genFunction.
2630             */
2631            saveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2632            restoreBank = TRUE;
2633       }
2634       swapBanks = TRUE;
2635   }
2636
2637     /* if caller saves & we have not saved then */
2638     if (!ic->regsSaved)
2639       saveRegisters (ic);
2640
2641   /* if send set is not empty the assign */
2642   /* We've saved all the registers we care about;
2643   * therefore, we may clobber any register not used
2644   * in the calling convention (i.e. anything not in
2645   * fReturn.
2646   */
2647   if (_G.sendSet)
2648     {
2649         if (IFFUNC_ISREENT(dtype)) { /* need to reverse the send set */
2650             genSend(reverseSet(_G.sendSet));
2651         } else {
2652             genSend(_G.sendSet);
2653         }
2654       _G.sendSet = NULL;
2655     }
2656
2657   if (swapBanks)
2658   {
2659         emitcode ("mov", "psw,#!constbyte",
2660            ((FUNC_REGBANK(dtype)) << 3) & 0xff);
2661   }
2662
2663   /* make the call */
2664   emitcode ("lcall", "%s", (OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2665                             OP_SYMBOL (IC_LEFT (ic))->rname :
2666                             OP_SYMBOL (IC_LEFT (ic))->name));
2667
2668   if (swapBanks)
2669   {
2670        emitcode ("mov", "psw,#!constbyte",
2671           ((FUNC_REGBANK(currFunc->type)) << 3) & 0xff);
2672   }
2673
2674   /* if we need assign a result value */
2675   if ((IS_ITEMP (IC_RESULT (ic)) &&
2676        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2677         OP_SYMBOL (IC_RESULT (ic))->accuse ||
2678         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2679       IS_TRUE_SYMOP (IC_RESULT (ic)))
2680     {
2681       if (isOperandInFarSpace (IC_RESULT (ic))
2682           && getSize (operandType (IC_RESULT (ic))) <= 2)
2683         {
2684           int size = getSize (operandType (IC_RESULT (ic)));
2685
2686           /* Special case for 1 or 2 byte return in far space. */
2687           MOVA (fReturn[0]);
2688           if (size > 1)
2689             {
2690               emitcode ("mov", "b,%s", fReturn[1]);
2691               _G.bInUse++;
2692             }
2693
2694           _G.accInUse++;
2695           aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2696           _G.accInUse--;
2697
2698           if (size > 1)
2699             _G.bInUse--;
2700
2701           aopPut (AOP (IC_RESULT (ic)), "a", 0);
2702
2703           if (size > 1)
2704             {
2705               aopPut (AOP (IC_RESULT (ic)), "b", 1);
2706             }
2707           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2708         }
2709       else
2710         {
2711           _G.bInUse++;
2712           aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2713           _G.bInUse--;
2714
2715           assignResultValue (IC_RESULT (ic));
2716
2717           freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2718         }
2719     }
2720
2721   /* adjust the stack for parameters if
2722      required */
2723   if (ic->parmBytes) {
2724       int i;
2725       if (options.stack10bit) {
2726           if (ic->parmBytes <= 10) {
2727               emitcode(";","stack adjustment for parms");
2728               for (i=0; i < ic->parmBytes ; i++) {
2729                   emitcode("pop","acc");
2730               }
2731           } else {
2732               PROTECT_SP;
2733               emitcode ("clr","c");
2734               emitcode ("mov","a,sp");
2735               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2736               emitcode ("mov","sp,a");
2737               emitcode ("mov","a,esp");
2738               adjustEsp("a");
2739               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2740               emitcode ("mov","esp,a");
2741               UNPROTECT_SP;
2742           }
2743       } else {
2744           if (ic->parmBytes > 3) {
2745               emitcode ("mov", "a,%s", spname);
2746               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2747               emitcode ("mov", "%s,a", spname);
2748           } else
2749               for (i = 0; i < ic->parmBytes; i++)
2750                   emitcode ("dec", "%s", spname);
2751       }
2752   }
2753
2754   /* if we hade saved some registers then unsave them */
2755   if (ic->regsSaved)
2756     unsaveRegisters (ic);
2757
2758   /* if register bank was saved then pop them */
2759   if (restoreBank)
2760     unsaveRBank (FUNC_REGBANK (dtype), ic, FALSE);
2761 }
2762
2763 /*-----------------------------------------------------------------*/
2764 /* genPcall - generates a call by pointer statement                */
2765 /*-----------------------------------------------------------------*/
2766 static void
2767 genPcall (iCode * ic)
2768 {
2769   sym_link *dtype;
2770   symbol *rlbl = newiTempLabel (NULL);
2771   bool restoreBank=FALSE;
2772
2773   D (emitcode (";", "genPcall ");
2774     );
2775
2776
2777   /* if caller saves & we have not saved then */
2778   if (!ic->regsSaved)
2779     saveRegisters (ic);
2780
2781   /* if we are calling a function that is not using
2782      the same register bank then we need to save the
2783      destination registers on the stack */
2784   dtype = operandType (IC_LEFT (ic));
2785   if (currFunc && dtype && (!IFFUNC_ISNAKED(dtype) || TARGET_IS_DS400) &&
2786       IFFUNC_ISISR (currFunc->type) &&
2787       (FUNC_REGBANK (currFunc->type) != FUNC_REGBANK (dtype))) {
2788     saveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2789     restoreBank=TRUE;
2790   }
2791
2792   /* push the return address on to the stack */
2793   emitcode ("mov", "a,#!tlabel", (rlbl->key + 100));
2794   emitcode ("push", "acc");
2795   emitcode ("mov", "a,#!hil", (rlbl->key + 100));
2796   emitcode ("push", "acc");
2797
2798   if (options.model == MODEL_FLAT24)
2799     {
2800       emitcode ("mov", "a,#!hihil", (rlbl->key + 100));
2801       emitcode ("push", "acc");
2802     }
2803
2804   /* now push the calling address */
2805   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2806
2807   pushSide (IC_LEFT (ic), FPTRSIZE);
2808
2809   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
2810
2811   /* if send set is not empty the assign */
2812   if (_G.sendSet)
2813     {
2814         genSend(reverseSet(_G.sendSet));
2815         _G.sendSet = NULL;
2816     }
2817
2818   emitcode ("ret", "");
2819   emitcode ("", "!tlabeldef", (rlbl->key + 100));
2820
2821
2822   /* if we need assign a result value */
2823   if ((IS_ITEMP (IC_RESULT (ic)) &&
2824        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2825         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2826       IS_TRUE_SYMOP (IC_RESULT (ic)))
2827     {
2828
2829       _G.accInUse++;
2830       aopOp (IC_RESULT (ic), ic, FALSE, TRUE);
2831       _G.accInUse--;
2832
2833       assignResultValue (IC_RESULT (ic));
2834
2835       freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
2836     }
2837
2838   /* adjust the stack for parameters if
2839      required */
2840   if (ic->parmBytes)
2841     {
2842       int i;
2843       if (options.stack10bit) {
2844           if (ic->parmBytes <= 10) {
2845               emitcode(";","stack adjustment for parms");
2846               for (i=0; i < ic->parmBytes ; i++) {
2847                   emitcode("pop","acc");
2848               }
2849           } else {
2850               PROTECT_SP;
2851               emitcode ("clr","c");
2852               emitcode ("mov","a,sp");
2853               emitcode ("subb","a,#!constbyte",ic->parmBytes & 0xff);
2854               emitcode ("mov","sp,a");
2855               emitcode ("mov","a,esp");
2856               adjustEsp("a");
2857               emitcode ("subb","a,#!constbyte",(ic->parmBytes >> 8) & 0xff);
2858               emitcode ("mov","esp,a");
2859               UNPROTECT_SP;
2860           }
2861       } else {
2862           if (ic->parmBytes > 3) {
2863               emitcode ("mov", "a,%s", spname);
2864               emitcode ("add", "a,#!constbyte", (-ic->parmBytes) & 0xff);
2865               emitcode ("mov", "%s,a", spname);
2866           }
2867           else
2868               for (i = 0; i < ic->parmBytes; i++)
2869                   emitcode ("dec", "%s", spname);
2870
2871       }
2872     }
2873   /* if register bank was saved then unsave them */
2874   if (restoreBank)
2875     unsaveRBank (FUNC_REGBANK (dtype), ic, TRUE);
2876
2877   /* if we hade saved some registers then
2878      unsave them */
2879   if (ic->regsSaved)
2880     unsaveRegisters (ic);
2881
2882 }
2883
2884 /*-----------------------------------------------------------------*/
2885 /* resultRemat - result  is rematerializable                       */
2886 /*-----------------------------------------------------------------*/
2887 static int
2888 resultRemat (iCode * ic)
2889 {
2890   if (SKIP_IC (ic) || ic->op == IFX)
2891     return 0;
2892
2893   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2894     {
2895       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2896       if (sym->remat && !POINTER_SET (ic))
2897         return 1;
2898     }
2899
2900   return 0;
2901 }
2902
2903 #if defined(__BORLANDC__) || defined(_MSC_VER)
2904 #define STRCASECMP stricmp
2905 #else
2906 #define STRCASECMP strcasecmp
2907 #endif
2908
2909 /*-----------------------------------------------------------------*/
2910 /* inExcludeList - return 1 if the string is in exclude Reg list   */
2911 /*-----------------------------------------------------------------*/
2912 static int
2913 regsCmp(void *p1, void *p2)
2914 {
2915   return (STRCASECMP((char *)p1, (char *)(p2)) == 0);
2916 }
2917
2918 static bool
2919 inExcludeList (char *s)
2920 {
2921   const char *p = setFirstItem(options.excludeRegsSet);
2922
2923   if (p == NULL || STRCASECMP(p, "none") == 0)
2924     return FALSE;
2925
2926
2927   return isinSetWith(options.excludeRegsSet, s, regsCmp);
2928 }
2929
2930 /*-----------------------------------------------------------------*/
2931 /* genFunction - generated code for function entry                 */
2932 /*-----------------------------------------------------------------*/
2933 static void
2934 genFunction (iCode * ic)
2935 {
2936   symbol *sym;
2937   sym_link *ftype;
2938   bool   switchedPSW = FALSE;
2939
2940   D (emitcode (";", "genFunction "););
2941
2942   _G.nRegsSaved = 0;
2943   /* create the function header */
2944   emitcode (";", "-----------------------------------------");
2945   emitcode (";", " function %s", (sym = OP_SYMBOL (IC_LEFT (ic)))->name);
2946   emitcode (";", "-----------------------------------------");
2947
2948   emitcode ("", "%s:", sym->rname);
2949   ftype = operandType (IC_LEFT (ic));
2950
2951   if (IFFUNC_ISNAKED(ftype))
2952   {
2953       emitcode(";", "naked function: no prologue.");
2954       return;
2955   }
2956
2957   if (options.stack_probe)
2958       emitcode ("lcall","__stack_probe");
2959
2960   /* here we need to generate the equates for the
2961      register bank if required */
2962   if (FUNC_REGBANK (ftype) != rbank)
2963     {
2964       int i;
2965
2966       rbank = FUNC_REGBANK (ftype);
2967       for (i = 0; i < ds390_nRegs; i++)
2968         {
2969           if (regs390[i].print) {
2970               if (strcmp (regs390[i].base, "0") == 0)
2971                   emitcode ("", "%s !equ !constbyte",
2972                             regs390[i].dname,
2973                             8 * rbank + regs390[i].offset);
2974               else
2975                   emitcode ("", "%s !equ %s + !constbyte",
2976                             regs390[i].dname,
2977                             regs390[i].base,
2978                             8 * rbank + regs390[i].offset);
2979           }
2980         }
2981     }
2982
2983   /* if this is an interrupt service routine then
2984      save acc, b, dpl, dph  */
2985   if (IFFUNC_ISISR (sym->type))
2986       { /* is ISR */
2987       if (!inExcludeList ("acc"))
2988         emitcode ("push", "acc");
2989       if (!inExcludeList ("b"))
2990         emitcode ("push", "b");
2991       if (!inExcludeList ("dpl"))
2992         emitcode ("push", "dpl");
2993       if (!inExcludeList ("dph"))
2994         emitcode ("push", "dph");
2995       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
2996         {
2997           emitcode ("push", "dpx");
2998           /* Make sure we're using standard DPTR */
2999           emitcode ("push", "dps");
3000           emitcode ("mov", "dps,#0");
3001           if (options.stack10bit)
3002             {
3003               /* This ISR could conceivably use DPTR2. Better save it. */
3004               emitcode ("push", "dpl1");
3005               emitcode ("push", "dph1");
3006               emitcode ("push", "dpx1");
3007               emitcode ("push",  DP2_RESULT_REG);
3008             }
3009         }
3010       /* if this isr has no bank i.e. is going to
3011          run with bank 0 , then we need to save more
3012          registers :-) */
3013       if (!FUNC_REGBANK (sym->type))
3014         {
3015             int i;
3016
3017           /* if this function does not call any other
3018              function then we can be economical and
3019              save only those registers that are used */
3020           if (!IFFUNC_HASFCALL(sym->type))
3021             {
3022
3023               /* if any registers used */
3024               if (sym->regsUsed)
3025                 {
3026                   /* save the registers used */
3027                   for (i = 0; i < sym->regsUsed->size; i++)
3028                     {
3029                       if (bitVectBitValue (sym->regsUsed, i))
3030                         emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
3031                     }
3032                 }
3033             }
3034           else
3035             {
3036               /* this function has  a function call cannot
3037                  determines register usage so we will have to push the
3038                  entire bank */
3039               saveRBank (0, ic, FALSE);
3040               if (options.parms_in_bank1) {
3041                   for (i=0; i < 8 ; i++ ) {
3042                       emitcode ("push","%s",rb1regs[i]);
3043                   }
3044               }
3045             }
3046         }
3047         else
3048         {
3049             /* This ISR uses a non-zero bank.
3050              *
3051              * We assume that the bank is available for our
3052              * exclusive use.
3053              *
3054              * However, if this ISR calls a function which uses some
3055              * other bank, we must save that bank entirely.
3056              */
3057             unsigned long banksToSave = 0;
3058
3059             if (IFFUNC_HASFCALL(sym->type))
3060             {
3061
3062 #define MAX_REGISTER_BANKS 4
3063
3064                 iCode *i;
3065                 int ix;
3066
3067                 for (i = ic; i; i = i->next)
3068                 {
3069                     if (i->op == ENDFUNCTION)
3070                     {
3071                         /* we got to the end OK. */
3072                         break;
3073                     }
3074
3075                     if (i->op == CALL)
3076                     {
3077                         sym_link *dtype;
3078
3079                         dtype = operandType (IC_LEFT(i));
3080                         if (dtype
3081                          && FUNC_REGBANK(dtype) != FUNC_REGBANK(sym->type))
3082                         {
3083                              /* Mark this bank for saving. */
3084                              if (FUNC_REGBANK(dtype) >= MAX_REGISTER_BANKS)
3085                              {
3086                                  werror(E_NO_SUCH_BANK, FUNC_REGBANK(dtype));
3087                              }
3088                              else
3089                              {
3090                                  banksToSave |= (1 << FUNC_REGBANK(dtype));
3091                              }
3092
3093                              /* And note that we don't need to do it in
3094                               * genCall.
3095                               */
3096                              i->bankSaved = 1;
3097                         }
3098                     }
3099                     if (i->op == PCALL)
3100                     {
3101                         /* This is a mess; we have no idea what
3102                          * register bank the called function might
3103                          * use.
3104                          *
3105                          * The only thing I can think of to do is
3106                          * throw a warning and hope.
3107                          */
3108                         werror(W_FUNCPTR_IN_USING_ISR);
3109                     }
3110                 }
3111
3112                 if (banksToSave && options.useXstack)
3113                 {
3114                     /* Since we aren't passing it an ic,
3115                      * saveRBank will assume r0 is available to abuse.
3116                      *
3117                      * So switch to our (trashable) bank now, so
3118                      * the caller's R0 isn't trashed.
3119                      */
3120                     emitcode ("push", "psw");
3121                     emitcode ("mov", "psw,#!constbyte",
3122                               (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3123                     switchedPSW = TRUE;
3124                 }
3125
3126                 for (ix = 0; ix < MAX_REGISTER_BANKS; ix++)
3127                 {
3128                      if (banksToSave & (1 << ix))
3129                      {
3130                          saveRBank(ix, NULL, FALSE);
3131                      }
3132                 }
3133             }
3134             // TODO: this needs a closer look
3135             SPEC_ISR_SAVED_BANKS(currFunc->etype) = banksToSave;
3136         }
3137     }
3138   else
3139     {
3140       /* if callee-save to be used for this function
3141          then save the registers being used in this function */
3142       if (IFFUNC_CALLEESAVES(sym->type))
3143         {
3144           int i;
3145
3146           /* if any registers used */
3147           if (sym->regsUsed)
3148             {
3149               /* save the registers used */
3150               for (i = 0; i < sym->regsUsed->size; i++)
3151                 {
3152                   if (bitVectBitValue (sym->regsUsed, i))
3153                     {
3154                       emitcode ("push", "%s", ds390_regWithIdx (i)->dname);
3155                       _G.nRegsSaved++;
3156                     }
3157                 }
3158             }
3159         }
3160     }
3161
3162   /* set the register bank to the desired value */
3163   if ((FUNC_REGBANK (sym->type) || FUNC_ISISR (sym->type))
3164    && !switchedPSW)
3165     {
3166       emitcode ("push", "psw");
3167       emitcode ("mov", "psw,#!constbyte", (FUNC_REGBANK (sym->type) << 3) & 0x00ff);
3168     }
3169
3170   if ( (IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3171        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3172       if (options.stack10bit) {
3173           emitcode ("push","_bpx");
3174           emitcode ("push","_bpx+1");
3175           emitcode ("mov","_bpx,%s",spname);
3176           emitcode ("mov","_bpx+1,esp");
3177           adjustEsp("_bpx+1");
3178       } else {
3179           if (options.useXstack) {
3180               emitcode ("mov", "r0,%s", spname);
3181               emitcode ("mov", "a,_bp");
3182               emitcode ("movx", "@r0,a");
3183               emitcode ("inc", "%s", spname);
3184           } else {
3185               /* set up the stack */
3186               emitcode ("push", "_bp"); /* save the callers stack  */
3187           }
3188           emitcode ("mov", "_bp,%s", spname);
3189       }
3190   }
3191
3192   /* adjust the stack for the function */
3193   if (sym->stack) {
3194       int i = sym->stack;
3195       if (options.stack10bit) {
3196           if ( i > 1024) werror (W_STACK_OVERFLOW, sym->name);
3197           assert (sym->recvSize <= 4);
3198           if (sym->stack <= 8) {
3199               while (i--) emitcode ("push","acc");
3200           } else {
3201               PROTECT_SP;
3202               emitcode ("mov","a,sp");
3203               emitcode ("add","a,#!constbyte", ((short) sym->stack & 0xff));
3204               emitcode ("mov","sp,a");
3205               emitcode ("mov","a,esp");
3206               adjustEsp("a");
3207               emitcode ("addc","a,#!constbyte", (((short) sym->stack) >> 8) & 0xff);
3208               emitcode ("mov","esp,a");
3209               UNPROTECT_SP;
3210           }
3211       } else {
3212           if (i > 256)
3213               werror (W_STACK_OVERFLOW, sym->name);
3214
3215           if (i > 3 && sym->recvSize < 4) {
3216
3217               emitcode ("mov", "a,sp");
3218               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
3219               emitcode ("mov", "sp,a");
3220
3221           } else
3222               while (i--)
3223                   emitcode ("inc", "sp");
3224       }
3225   }
3226
3227   if (sym->xstack)
3228     {
3229
3230       emitcode ("mov", "a,_spx");
3231       emitcode ("add", "a,#!constbyte", ((char) sym->xstack & 0xff));
3232       emitcode ("mov", "_spx,a");
3233     }
3234
3235   /* if critical function then turn interrupts off */
3236   if (IFFUNC_ISCRITICAL (ftype))
3237     {
3238       symbol *tlbl = newiTempLabel (NULL);
3239       emitcode ("setb", "c");
3240       emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
3241       emitcode ("clr", "c");
3242       emitcode ("", "%05d$:", (tlbl->key + 100));
3243       emitcode ("push", "psw"); /* save old ea via c in psw */
3244     }
3245
3246 }
3247
3248 /*-----------------------------------------------------------------*/
3249 /* genEndFunction - generates epilogue for functions               */
3250 /*-----------------------------------------------------------------*/
3251 static void
3252 genEndFunction (iCode * ic)
3253 {
3254   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
3255   lineNode *lnp = lineCurr;
3256   bitVect *regsUsed;
3257   bitVect *regsUsedPrologue;
3258   bitVect *regsUnneeded;
3259   int idx;
3260
3261   D (emitcode (";", "genEndFunction "););
3262
3263   if (IFFUNC_ISNAKED(sym->type))
3264   {
3265       emitcode(";", "naked function: no epilogue.");
3266       if (options.debug && currFunc)
3267         debugFile->writeEndFunction (currFunc, ic, 0);
3268       return;
3269   }
3270
3271   if (IFFUNC_ISCRITICAL (sym->type))
3272     {
3273       emitcode ("pop", "psw"); /* restore ea via c in psw */
3274       emitcode ("mov", "ea,c");
3275     }
3276
3277   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3278        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3279
3280       if (options.stack10bit) {
3281           PROTECT_SP;
3282           emitcode ("mov", "sp,_bpx", spname);
3283           emitcode ("mov", "esp,_bpx+1", spname);
3284           UNPROTECT_SP;
3285       } else {
3286           emitcode ("mov", "%s,_bp", spname);
3287       }
3288   }
3289
3290   /* if use external stack but some variables were
3291      added to the local stack then decrement the
3292      local stack */
3293   if (options.useXstack && sym->stack) {
3294       emitcode ("mov", "a,sp");
3295       emitcode ("add", "a,#!constbyte", ((char) -sym->stack) & 0xff);
3296       emitcode ("mov", "sp,a");
3297   }
3298
3299
3300   if ((IFFUNC_ISREENT (sym->type) || options.stackAuto) &&
3301        (sym->stack || FUNC_HASSTACKPARM(sym->type))) {
3302
3303       if (options.useXstack) {
3304           emitcode ("mov", "r0,%s", spname);
3305           emitcode ("movx", "a,@r0");
3306           emitcode ("mov", "_bp,a");
3307           emitcode ("dec", "%s", spname);
3308       } else {
3309           if (options.stack10bit) {
3310               emitcode ("pop", "_bpx+1");
3311               emitcode ("pop", "_bpx");
3312           } else {
3313               emitcode ("pop", "_bp");
3314           }
3315       }
3316   }
3317
3318   /* restore the register bank  */
3319   if (FUNC_REGBANK (sym->type) || IFFUNC_ISISR (sym->type))
3320   {
3321     if (!FUNC_REGBANK (sym->type) || !IFFUNC_ISISR (sym->type)
3322      || !options.useXstack)
3323     {
3324         /* Special case of ISR using non-zero bank with useXstack
3325          * is handled below.
3326          */
3327         emitcode ("pop", "psw");
3328     }
3329   }
3330
3331   if (IFFUNC_ISISR (sym->type))
3332       { /* is ISR */
3333
3334       /* now we need to restore the registers */
3335       /* if this isr has no bank i.e. is going to
3336          run with bank 0 , then we need to save more
3337          registers :-) */
3338       if (!FUNC_REGBANK (sym->type))
3339         {
3340             int i;
3341           /* if this function does not call any other
3342              function then we can be economical and
3343              save only those registers that are used */
3344           if (!IFFUNC_HASFCALL(sym->type))
3345             {
3346
3347               /* if any registers used */
3348               if (sym->regsUsed)
3349                 {
3350                   /* save the registers used */
3351                   for (i = sym->regsUsed->size; i >= 0; i--)
3352                     {
3353                       if (bitVectBitValue (sym->regsUsed, i))
3354                         emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3355                     }
3356                 }
3357             }
3358           else
3359             {
3360               /* this function has  a function call cannot
3361                  determines register usage so we will have to pop the
3362                  entire bank */
3363               if (options.parms_in_bank1) {
3364                   for (i = 7 ; i >= 0 ; i-- ) {
3365                       emitcode ("pop","%s",rb1regs[i]);
3366                   }
3367               }
3368               unsaveRBank (0, ic, FALSE);
3369             }
3370         }
3371         else
3372         {
3373             /* This ISR uses a non-zero bank.
3374              *
3375              * Restore any register banks saved by genFunction
3376              * in reverse order.
3377              */
3378             unsigned savedBanks = SPEC_ISR_SAVED_BANKS(currFunc->etype);
3379             int ix;
3380
3381             for (ix = MAX_REGISTER_BANKS - 1; ix >= 0; ix--)
3382             {
3383                 if (savedBanks & (1 << ix))
3384                 {
3385                     unsaveRBank(ix, NULL, FALSE);
3386                 }
3387             }
3388
3389             if (options.useXstack)
3390             {
3391                 /* Restore bank AFTER calling unsaveRBank,
3392                  * since it can trash r0.
3393                  */
3394                 emitcode ("pop", "psw");
3395             }
3396         }
3397
3398       if (options.model == MODEL_FLAT24 && !inExcludeList ("dpx"))
3399         {
3400           if (options.stack10bit)
3401             {
3402               emitcode ("pop", DP2_RESULT_REG);
3403               emitcode ("pop", "dpx1");
3404               emitcode ("pop", "dph1");
3405               emitcode ("pop", "dpl1");
3406             }
3407           emitcode ("pop", "dps");
3408           emitcode ("pop", "dpx");
3409         }
3410       if (!inExcludeList ("dph"))
3411         emitcode ("pop", "dph");
3412       if (!inExcludeList ("dpl"))
3413         emitcode ("pop", "dpl");
3414       if (!inExcludeList ("b"))
3415         emitcode ("pop", "b");
3416       if (!inExcludeList ("acc"))
3417         emitcode ("pop", "acc");
3418
3419       /* if debug then send end of function */
3420       if (options.debug && currFunc) {
3421           debugFile->writeEndFunction (currFunc, ic, 1);
3422         }
3423
3424       emitcode ("reti", "");
3425     }
3426   else
3427     {
3428       if (IFFUNC_CALLEESAVES(sym->type))
3429         {
3430           int i;
3431
3432           /* if any registers used */
3433           if (sym->regsUsed)
3434             {
3435               /* save the registers used */
3436               for (i = sym->regsUsed->size; i >= 0; i--)
3437                 {
3438                   if (bitVectBitValue (sym->regsUsed, i))
3439                     emitcode ("pop", "%s", ds390_regWithIdx (i)->dname);
3440                 }
3441             }
3442         }
3443
3444       /* if debug then send end of function */
3445       if (options.debug && currFunc)
3446         {
3447           debugFile->writeEndFunction (currFunc, ic, 1);
3448         }
3449
3450       emitcode ("ret", "");
3451     }
3452
3453   if (!port->peep.getRegsRead || !port->peep.getRegsWritten || options.nopeep)
3454     return;
3455
3456   /* If this was an interrupt handler using bank 0 that called another */
3457   /* function, then all registers must be saved; nothing to optimized. */
3458   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type)
3459       && !FUNC_REGBANK(sym->type))
3460     return;
3461
3462   /* There are no push/pops to optimize if not callee-saves or ISR */
3463   if (!(FUNC_CALLEESAVES (sym->type) || FUNC_ISISR (sym->type)))
3464     return;
3465
3466   /* If there were stack parameters, we cannot optimize without also    */
3467   /* fixing all of the stack offsets; this is too dificult to consider. */
3468   if (FUNC_HASSTACKPARM(sym->type))
3469     return;
3470
3471   /* Compute the registers actually used */
3472   regsUsed = newBitVect (ds390_nRegs);
3473   regsUsedPrologue = newBitVect (ds390_nRegs);
3474   while (lnp)
3475     {
3476       if (lnp->ic && lnp->ic->op == FUNCTION)
3477         regsUsedPrologue = bitVectUnion (regsUsedPrologue, port->peep.getRegsWritten(lnp));
3478       else
3479         regsUsed = bitVectUnion (regsUsed, port->peep.getRegsWritten(lnp));
3480
3481       if (lnp->ic && lnp->ic->op == FUNCTION && lnp->prev
3482           && lnp->prev->ic && lnp->prev->ic->op == ENDFUNCTION)
3483         break;
3484       if (!lnp->prev)
3485         break;
3486       lnp = lnp->prev;
3487     }
3488
3489   if (bitVectBitValue (regsUsedPrologue, DPS_IDX)
3490       && !bitVectBitValue (regsUsed, DPS_IDX))
3491     {
3492       bitVectUnSetBit (regsUsedPrologue, DPS_IDX);
3493     }
3494
3495   if (bitVectBitValue (regsUsedPrologue, CND_IDX)
3496       && !bitVectBitValue (regsUsed, CND_IDX))
3497     {
3498       regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3499       if (IFFUNC_ISISR (sym->type) && !FUNC_REGBANK (sym->type)
3500           && !sym->stack && !FUNC_ISCRITICAL (sym->type))
3501         bitVectUnSetBit (regsUsed, CND_IDX);
3502     }
3503   else
3504     regsUsed = bitVectUnion (regsUsed, regsUsedPrologue);
3505
3506   /* If this was an interrupt handler that called another function */
3507   /* function, then assume working registers may be modified by it. */
3508   if (IFFUNC_ISISR (sym->type) && IFFUNC_HASFCALL(sym->type))
3509     {
3510       regsUsed = bitVectSetBit (regsUsed, AP_IDX);
3511       regsUsed = bitVectSetBit (regsUsed, DPX1_IDX);
3512       regsUsed = bitVectSetBit (regsUsed, DPL1_IDX);
3513       regsUsed = bitVectSetBit (regsUsed, DPH1_IDX);
3514       regsUsed = bitVectSetBit (regsUsed, DPX_IDX);
3515       regsUsed = bitVectSetBit (regsUsed, DPL_IDX);
3516       regsUsed = bitVectSetBit (regsUsed, DPH_IDX);
3517       regsUsed = bitVectSetBit (regsUsed, DPS_IDX);
3518       regsUsed = bitVectSetBit (regsUsed, B_IDX);
3519       regsUsed = bitVectSetBit (regsUsed, A_IDX);
3520       regsUsed = bitVectSetBit (regsUsed, CND_IDX);
3521     }
3522
3523   /* Remove the unneeded push/pops */
3524   regsUnneeded = newBitVect (ds390_nRegs);
3525   while (lnp)
3526     {
3527       if (lnp->ic && (lnp->ic->op == FUNCTION || lnp->ic->op == ENDFUNCTION))
3528         {
3529           if (!strncmp(lnp->line, "push", 4))
3530             {
3531               idx = bitVectFirstBit (port->peep.getRegsRead(lnp));
3532               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3533                 {
3534                   connectLine (lnp->prev, lnp->next);
3535                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3536                 }
3537             }
3538           if (!strncmp(lnp->line, "pop", 3) || !strncmp(lnp->line, "mov", 3))
3539             {
3540               idx = bitVectFirstBit (port->peep.getRegsWritten(lnp));
3541               if (idx>=0 && !bitVectBitValue (regsUsed, idx))
3542                 {
3543                   connectLine (lnp->prev, lnp->next);
3544                   regsUnneeded = bitVectSetBit (regsUnneeded, idx);
3545                 }
3546             }
3547         }
3548       lnp = lnp->next;
3549     }
3550
3551   for (idx = 0; idx < regsUnneeded->size; idx++)
3552     if (bitVectBitValue (regsUnneeded, idx))
3553       emitcode ("", ";\teliminated unneeded push/pop %s", ds390_regWithIdx (idx)->dname);
3554
3555   freeBitVect (regsUnneeded);
3556   freeBitVect (regsUsed);
3557   freeBitVect (regsUsedPrologue);
3558 }
3559
3560 /*-----------------------------------------------------------------*/
3561 /* genJavaNativeRet - generate code for return JavaNative          */
3562 /*-----------------------------------------------------------------*/
3563 static void genJavaNativeRet(iCode *ic)
3564 {
3565     int i, size;
3566
3567     aopOp (IC_LEFT (ic), ic, FALSE,
3568            AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE);
3569     size = AOP_SIZE (IC_LEFT (ic));
3570
3571     assert (size <= 4);
3572
3573     /* it is assigned to GPR0-R3 then push them */
3574     if (aopHasRegs(AOP(IC_LEFT(ic)),R0_IDX,R1_IDX) ||
3575         aopHasRegs(AOP(IC_LEFT(ic)),R2_IDX,R3_IDX)) {
3576         for (i = 0 ; i < size ; i++ ) {
3577             emitcode ("push","%s",
3578                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3579         }
3580         for (i = (size-1) ; i >= 0 ; i--) {
3581             emitcode ("pop","a%s",javaRet[i]);
3582         }
3583     } else {
3584         for (i = 0 ; i < size ; i++)
3585             emitcode ("mov","%s,%s",javaRet[i],
3586                       aopGet(AOP(IC_LEFT(ic)),i,FALSE,TRUE,DP2_RESULT_REG));
3587     }
3588     for (i = size ; i < 4 ; i++ )
3589             emitcode ("mov","%s,#0",javaRet[i]);
3590     return;
3591 }
3592
3593 /*-----------------------------------------------------------------*/
3594 /* genRet - generate code for return statement                     */
3595 /*-----------------------------------------------------------------*/
3596 static void
3597 genRet (iCode * ic)
3598 {
3599   int size, offset = 0, pushed = 0;
3600
3601   D (emitcode (";", "genRet "););
3602
3603   /* if we have no return value then
3604      just generate the "ret" */
3605   if (!IC_LEFT (ic))
3606     goto jumpret;
3607
3608   /* if this is a JavaNative function then return
3609      value in different register */
3610   if (IFFUNC_ISJAVANATIVE(currFunc->type)) {
3611       genJavaNativeRet(ic);
3612       goto jumpret;
3613   }
3614   /* we have something to return then
3615      move the return value into place */
3616   aopOp (IC_LEFT (ic), ic, FALSE,
3617          (AOP_IS_STR(IC_LEFT(ic)) ? FALSE :TRUE));
3618   size = AOP_SIZE (IC_LEFT (ic));
3619
3620   _startLazyDPSEvaluation ();
3621   while (size--)
3622     {
3623       char *l;
3624       if (AOP_TYPE (IC_LEFT (ic)) == AOP_DPTR)
3625         {
3626           l = aopGet (AOP (IC_LEFT (ic)), offset++,
3627                       FALSE, TRUE, NULL);
3628           emitcode ("push", "%s", l);
3629           pushed++;
3630         }
3631       else
3632         {
3633           /* Since A is the last element of fReturn,
3634            * is is OK to clobber it in the aopGet.
3635            */
3636           l = aopGet (AOP (IC_LEFT (ic)), offset,
3637                       FALSE, FALSE, NULL);
3638           if (strcmp (fReturn[offset], l))
3639             emitcode ("mov", "%s,%s", fReturn[offset++], l);
3640         }
3641     }
3642   _endLazyDPSEvaluation ();
3643
3644   if (pushed)
3645     {
3646       while (pushed)
3647         {
3648           pushed--;
3649           if (strcmp (fReturn[pushed], "a"))
3650             emitcode ("pop", fReturn[pushed]);
3651           else
3652             emitcode ("pop", "acc");
3653         }
3654     }
3655   freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
3656
3657 jumpret:
3658   /* generate a jump to the return label
3659      if the next is not the return statement */
3660   if (!(ic->next && ic->next->op == LABEL &&
3661         IC_LABEL (ic->next) == returnLabel))
3662
3663     emitcode ("ljmp", "!tlabel", (returnLabel->key + 100));
3664
3665 }
3666
3667 /*-----------------------------------------------------------------*/
3668 /* genLabel - generates a label                                    */
3669 /*-----------------------------------------------------------------*/
3670 static void
3671 genLabel (iCode * ic)
3672 {
3673   /* special case never generate */
3674   if (IC_LABEL (ic) == entryLabel)
3675     return;
3676
3677   D (emitcode (";", "genLabel ");
3678     );
3679
3680   emitcode ("", "!tlabeldef", (IC_LABEL (ic)->key + 100));
3681 }
3682
3683 /*-----------------------------------------------------------------*/
3684 /* genGoto - generates a ljmp                                      */
3685 /*-----------------------------------------------------------------*/
3686 static void
3687 genGoto (iCode * ic)
3688 {
3689   D (emitcode (";", "genGoto ");
3690     );
3691   emitcode ("ljmp", "!tlabel", (IC_LABEL (ic)->key + 100));
3692 }
3693
3694 /*-----------------------------------------------------------------*/
3695 /* findLabelBackwards: walks back through the iCode chain looking  */
3696 /* for the given label. Returns number of iCode instructions     */
3697 /* between that label and given ic.          */
3698 /* Returns zero if label not found.          */
3699 /*-----------------------------------------------------------------*/
3700 static int
3701 findLabelBackwards (iCode * ic, int key)
3702 {
3703   int count = 0;
3704
3705   while (ic->prev)
3706     {
3707       ic = ic->prev;
3708       count++;
3709
3710       /* If we have any pushes or pops, we cannot predict the distance.
3711          I don't like this at all, this should be dealt with in the
3712          back-end */
3713       if (ic->op == IPUSH || ic->op == IPOP) {
3714         return 0;
3715       }
3716
3717       if (ic->op == LABEL && IC_LABEL (ic)->key == key)
3718         {
3719           /* printf("findLabelBackwards = %d\n", count); */
3720           return count;
3721         }
3722     }
3723
3724   return 0;
3725 }
3726
3727 /*-----------------------------------------------------------------*/
3728 /* genPlusIncr :- does addition with increment if possible         */
3729 /*-----------------------------------------------------------------*/
3730 static bool
3731 genPlusIncr (iCode * ic)
3732 {
3733   unsigned int icount;
3734   unsigned int size = getDataSize (IC_RESULT (ic));
3735
3736   /* will try to generate an increment */
3737   /* if the right side is not a literal
3738      we cannot */
3739   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3740     return FALSE;
3741
3742   /* if the literal value of the right hand side
3743      is greater than 4 then it is not worth it */
3744   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
3745     return FALSE;
3746
3747   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
3748       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
3749       while (icount--) {
3750           emitcode("inc","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
3751       }
3752       return TRUE;
3753   }
3754   /* if increment 16 bits in register */
3755   if (
3756        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3757        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3758        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3759        (size > 1) &&
3760        (icount == 1))
3761     {
3762       symbol  *tlbl;
3763       int     emitTlbl;
3764       int     labelRange;
3765       char    *l;
3766
3767       /* If the next instruction is a goto and the goto target
3768        * is <= 5 instructions previous to this, we can generate
3769        * jumps straight to that target.
3770        */
3771       if (ic->next && ic->next->op == GOTO
3772           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
3773           && labelRange <= 5)
3774         {
3775           D(emitcode (";", "tail increment optimized (range %d)", labelRange););
3776           tlbl = IC_LABEL (ic->next);
3777           emitTlbl = 0;
3778         }
3779       else
3780         {
3781           tlbl = newiTempLabel (NULL);
3782           emitTlbl = 1;
3783         }
3784
3785       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
3786       emitcode ("inc", "%s", l);
3787
3788       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3789           IS_AOP_PREG (IC_RESULT (ic)))
3790         {
3791           emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3792         }
3793       else
3794         {
3795           emitcode ("clr", "a");
3796           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3797         }
3798
3799       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL);
3800       emitcode ("inc", "%s", l);
3801       if (size > 2)
3802         {
3803           if (!strcmp(l, "acc"))
3804             {
3805                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3806             }
3807           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3808                    IS_AOP_PREG (IC_RESULT (ic)))
3809             {
3810                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3811             }
3812           else
3813             {
3814                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3815             }
3816
3817           l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
3818           emitcode ("inc", "%s", l);
3819         }
3820       if (size > 3)
3821         {
3822           if (!strcmp(l, "acc"))
3823             {
3824                 emitcode("jnz", "!tlabel", tlbl->key + 100);
3825             }
3826           else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
3827                    IS_AOP_PREG (IC_RESULT (ic)))
3828             {
3829                 emitcode ("cjne", "%s,#0,!tlabel", l, tlbl->key + 100);
3830             }
3831           else
3832             {
3833                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
3834             }
3835
3836           l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
3837           emitcode ("inc", "%s", l);
3838         }
3839
3840       if (emitTlbl)
3841         {
3842           emitcode ("", "!tlabeldef", tlbl->key + 100);
3843         }
3844       return TRUE;
3845     }
3846
3847   if (AOP_TYPE(IC_RESULT(ic))==AOP_STR && IS_ITEMP(IC_RESULT(ic)) &&
3848       !AOP_USESDPTR(IC_LEFT(ic)) && icount <= 5 && size <= 3 &&
3849       options.model == MODEL_FLAT24 )
3850     {
3851       if (IC_RESULT(ic)->isGptr)
3852         {
3853           emitcode ("mov","b,%s",aopGet(AOP (IC_LEFT (ic)), 3, FALSE, FALSE, NULL));
3854         }
3855       switch (size) {
3856       case 3:
3857           emitcode ("mov","dpx,%s",aopGet(AOP (IC_LEFT (ic)), 2, FALSE, FALSE, NULL));
3858       case 2:
3859           emitcode ("mov","dph,%s",aopGet(AOP (IC_LEFT (ic)), 1, FALSE, FALSE, NULL));
3860       case 1:
3861           emitcode ("mov","dpl,%s",aopGet(AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3862           break;
3863       }
3864       while (icount--) emitcode ("inc","dptr");
3865       return TRUE;
3866   }
3867
3868   if (AOP_INDPTRn(IC_LEFT(ic)) && AOP_INDPTRn(IC_RESULT(ic)) &&
3869       AOP(IC_LEFT(ic))->aopu.dptr == AOP(IC_RESULT(ic))->aopu.dptr &&
3870       icount <= 5 ) {
3871       emitcode ("mov","dps,#!constbyte",AOP(IC_LEFT(ic))->aopu.dptr);
3872       while (icount--) emitcode ("inc","dptr");
3873       emitcode ("mov","dps,#0");
3874       return TRUE;
3875   }
3876
3877   /* if the sizes are greater than 1 then we cannot */
3878   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3879       AOP_SIZE (IC_LEFT (ic)) > 1)
3880     return FALSE;
3881
3882   /* we can if the aops of the left & result match or
3883      if they are in registers and the registers are the
3884      same */
3885   if (
3886        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
3887        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
3888        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3889     {
3890
3891       if (icount > 3)
3892         {
3893           MOVA (aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3894           emitcode ("add", "a,#!constbyte", ((char) icount) & 0xff);
3895           aopPut (AOP (IC_RESULT (ic)), "a", 0);
3896         }
3897       else
3898         {
3899
3900           _startLazyDPSEvaluation ();
3901           while (icount--)
3902             {
3903               emitcode ("inc", "%s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE, FALSE, NULL));
3904             }
3905           _endLazyDPSEvaluation ();
3906         }
3907
3908       return TRUE;
3909     }
3910
3911   return FALSE;
3912 }
3913
3914 /*-----------------------------------------------------------------*/
3915 /* outBitAcc - output a bit in acc                                 */
3916 /*-----------------------------------------------------------------*/
3917 static void
3918 outBitAcc (operand * result)
3919 {
3920   symbol *tlbl = newiTempLabel (NULL);
3921   /* if the result is a bit */
3922   if (AOP_TYPE (result) == AOP_CRY)
3923     {
3924       aopPut (AOP (result), "a", 0);
3925     }
3926   else
3927     {
3928       emitcode ("jz", "!tlabel", tlbl->key + 100);
3929       emitcode ("mov", "a,%s", one);
3930       emitcode ("", "!tlabeldef", tlbl->key + 100);
3931       outAcc (result);
3932     }
3933 }
3934
3935 /*-----------------------------------------------------------------*/
3936 /* genPlusBits - generates code for addition of two bits           */
3937 /*-----------------------------------------------------------------*/
3938 static void
3939 genPlusBits (iCode * ic)
3940 {
3941   D (emitcode (";", "genPlusBits "););
3942
3943   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
3944     {
3945       symbol *lbl = newiTempLabel (NULL);
3946       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3947       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
3948       emitcode ("cpl", "c");
3949       emitcode ("", "!tlabeldef", (lbl->key + 100));
3950       outBitC (IC_RESULT (ic));
3951     }
3952   else
3953     {
3954       emitcode ("clr", "a");
3955       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
3956       emitcode ("rlc", "a");
3957       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
3958       emitcode ("addc", "a,#0");
3959       outAcc (IC_RESULT (ic));
3960     }
3961 }
3962
3963 static void
3964 adjustArithmeticResult (iCode * ic)
3965 {
3966   if (opIsGptr (IC_RESULT (ic)) &&
3967       opIsGptr (IC_LEFT (ic)) &&
3968       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3969     {
3970       aopPut (AOP (IC_RESULT (ic)),
3971               aopGet (AOP (IC_LEFT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3972               GPTRSIZE - 1);
3973     }
3974
3975   if (opIsGptr (IC_RESULT (ic)) &&
3976       opIsGptr (IC_RIGHT (ic)) &&
3977       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3978     {
3979       aopPut (AOP (IC_RESULT (ic)),
3980             aopGet (AOP (IC_RIGHT (ic)), GPTRSIZE - 1, FALSE, FALSE, NULL),
3981               GPTRSIZE - 1);
3982     }
3983
3984   if (opIsGptr (IC_RESULT (ic)) &&
3985       AOP_SIZE (IC_LEFT (ic)) < GPTRSIZE &&
3986       AOP_SIZE (IC_RIGHT (ic)) < GPTRSIZE &&
3987       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))) &&
3988       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_RIGHT (ic))))
3989     {
3990       char buff[5];
3991       SNPRINTF (buff, sizeof(buff),
3992                 "#%d", pointerCode (getSpec (operandType (IC_LEFT (ic)))));
3993       aopPut (AOP (IC_RESULT (ic)), buff, GPTRSIZE - 1);
3994     }
3995 }
3996
3997 // The guts of AOP_OP_3_NOFATAL. Generates the left & right opcodes of an IC,
3998 // generates the result if possible. If result is generated, returns TRUE; otherwise
3999 // returns false and caller must deal with fact that result isn't aopOp'd.
4000 bool aopOp3(iCode * ic)
4001 {
4002     bool dp1InUse, dp2InUse;
4003     bool useDp2;
4004
4005     // First, generate the right opcode. DPTR may be used if neither left nor result are
4006     // of type AOP_STR.
4007
4008 //    D(emitcode(";", "aopOp3: AOP_IS_STR left: %s right: %s result: %s",
4009 //             AOP_IS_STR(IC_LEFT(ic)) ? "true" : "false",
4010 //             AOP_IS_STR(IC_RIGHT(ic)) ? "true" : "false",
4011 //             AOP_IS_STR(IC_RESULT(ic)) ? "true" : "false");
4012 //      );
4013 //    D(emitcode(";", "aopOp3: AOP_IS_DPTRn left: %s right: %s result: %s",
4014 //             AOP_IS_DPTRn(IC_LEFT(ic)) ? "true" : "false",
4015 //             AOP_IS_DPTRn(IC_RIGHT(ic)) ? "true" : "false",
4016 //             AOP_IS_DPTRn(IC_RESULT(ic)) ? "true" : "false");
4017 //      );
4018
4019     // Right uses DPTR unless left or result is an AOP_STR; however,
4020     // if right is an AOP_STR, it must use DPTR regardless.
4021     if ((AOP_IS_STR(IC_LEFT(ic)) || AOP_IS_STR(IC_RESULT(ic)))
4022      && !AOP_IS_STR(IC_RIGHT(ic)))
4023     {
4024         useDp2 = TRUE;
4025     }
4026     else
4027     {
4028         useDp2 = FALSE;
4029     }
4030
4031     aopOp (IC_RIGHT(ic),ic,FALSE, useDp2);
4032
4033     // if the right used DPTR, left MUST use DPTR2.
4034     // if the right used DPTR2, left MUST use DPTR.
4035     // if both are still available, we prefer to use DPTR. But if result is an AOP_STR
4036     // and left is not an AOP_STR, then we will get better code if we use DP2 for left,
4037     // enabling us to assign DPTR to result.
4038
4039     if (AOP_USESDPTR(IC_RIGHT(ic)))
4040     {
4041         useDp2 = TRUE;
4042     }
4043     else if (AOP_USESDPTR2(IC_RIGHT(ic)))
4044     {
4045         useDp2 = FALSE;
4046     }
4047     else
4048     {
4049         if (AOP_IS_STR(IC_RESULT(ic)) && !AOP_IS_STR(IC_LEFT(ic)))
4050         {
4051             useDp2 = TRUE;
4052         }
4053         else
4054         {
4055             useDp2 = FALSE;
4056         }
4057     }
4058
4059     aopOp(IC_LEFT(ic), ic, FALSE, useDp2);
4060
4061
4062     // We've op'd the left & right. So, if left or right are the same operand as result,
4063     // we know aopOp will succeed, and we can just do it & bail.
4064     if (isOperandEqual(IC_LEFT(ic),IC_RESULT(ic)))
4065       {
4066         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4067         return TRUE;
4068       }
4069     if (isOperandEqual(IC_RIGHT(ic),IC_RESULT(ic)))
4070       {
4071 //      D(emitcode(";", "aopOp3: (left | right) & result equal"););
4072         aopOp(IC_RESULT(ic),ic,TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4073         return TRUE;
4074       }
4075
4076     // Operands may be equivalent (but not equal) if they share a spill location. If
4077     // so, use the same DPTR or DPTR2.
4078     if (operandsEqu (IC_LEFT(ic), IC_RESULT(ic)))
4079       {
4080         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_LEFT (ic)));
4081         return TRUE;
4082       }
4083     if (operandsEqu (IC_RIGHT(ic), IC_RESULT(ic)))
4084       {
4085         aopOp (IC_RESULT (ic), ic, TRUE, AOP_USESDPTR2 (IC_RIGHT (ic)));
4086         return TRUE;
4087       }
4088
4089     // Note which dptrs are currently in use.
4090     dp1InUse = AOP_USESDPTR(IC_LEFT(ic)) || AOP_USESDPTR(IC_RIGHT(ic));
4091     dp2InUse = AOP_USESDPTR2(IC_LEFT(ic)) || AOP_USESDPTR2(IC_RIGHT(ic));
4092
4093     // OK, now if either left or right uses DPTR and the result is an AOP_STR, we cannot
4094     // generate it.
4095     if (dp1InUse && AOP_IS_STR(IC_RESULT(ic)))
4096     {
4097         return FALSE;
4098     }
4099
4100     // Likewise, if left or right uses DPTR2 and the result is a DPTRn, we cannot generate it.
4101     if (dp2InUse && AOP_IS_DPTRn(IC_RESULT(ic)))
4102     {
4103         return FALSE;
4104     }
4105
4106     // or, if both dp1 & dp2 are in use and the result needs a dptr, we're out of luck
4107     if (dp1InUse && dp2InUse && isOperandInFarSpace(IC_RESULT(ic)))
4108     {
4109         return FALSE;
4110     }
4111
4112     aopOp (IC_RESULT(ic),ic,TRUE, dp1InUse);
4113
4114     // Some sanity checking...
4115     if (dp1InUse && AOP_USESDPTR(IC_RESULT(ic)))
4116     {
4117         fprintf(stderr,
4118                 "Internal error: got unexpected DPTR (%s:%d %s:%d)\n",
4119                 __FILE__, __LINE__, ic->filename, ic->lineno);
4120         emitcode(";", ">>> unexpected DPTR here.");
4121     }
4122
4123     if (dp2InUse && AOP_USESDPTR2(IC_RESULT(ic)))
4124     {
4125         fprintf(stderr,
4126                 "Internal error: got unexpected DPTR2 (%s:%d %s:%d)\n",
4127                 __FILE__, __LINE__, ic->filename, ic->lineno);
4128         emitcode(";", ">>> unexpected DPTR2 here.");
4129     }
4130
4131     return TRUE;
4132 }
4133
4134 // Macro to aopOp all three operands of an ic. If this cannot be done,
4135 // the IC_LEFT and IC_RIGHT operands will be aopOp'd, and the rc parameter
4136 // will be set TRUE. The caller must then handle the case specially, noting
4137 // that the IC_RESULT operand is not aopOp'd.
4138 //
4139 #define AOP_OP_3_NOFATAL(ic, rc) \
4140             do { rc = !aopOp3(ic); } while (0)
4141
4142 // aopOp the left & right operands of an ic.
4143 #define AOP_OP_2(ic) \
4144     aopOp (IC_RIGHT(ic),ic,FALSE, AOP_IS_STR(IC_LEFT(ic))); \
4145     aopOp (IC_LEFT(ic),ic,FALSE, AOP_USESDPTR(IC_RIGHT(ic)));
4146
4147 // convienience macro.
4148 #define AOP_SET_LOCALS(ic) \
4149     left = IC_LEFT(ic); \
4150     right = IC_RIGHT(ic); \
4151     result = IC_RESULT(ic);
4152
4153
4154 // Given an integer value of pushedSize bytes on the stack,
4155 // adjust it to be resultSize bytes, either by discarding
4156 // the most significant bytes or by zero-padding.
4157 //
4158 // On exit from this macro, pushedSize will have been adjusted to
4159 // equal resultSize, and ACC may be trashed.
4160 #define ADJUST_PUSHED_RESULT(pushedSize, resultSize)            \
4161       /* If the pushed data is bigger than the result,          \
4162        * simply discard unused bytes. Icky, but works.          \
4163        */                                                       \
4164       while (pushedSize > resultSize)                           \
4165       {                                                         \
4166           D (emitcode (";", "discarding unused result byte."););\
4167           emitcode ("pop", "acc");                              \
4168           pushedSize--;                                         \
4169       }                                                         \
4170       if (pushedSize < resultSize)                              \
4171       {                                                         \
4172           emitcode ("clr", "a");                                \
4173           /* Conversly, we haven't pushed enough here.          \
4174            * just zero-pad, and all is well.                    \
4175            */                                                   \
4176           while (pushedSize < resultSize)                       \
4177           {                                                     \
4178               emitcode("push", "acc");                          \
4179               pushedSize++;                                     \
4180           }                                                     \
4181       }                                                         \
4182       assert(pushedSize == resultSize);
4183
4184 /*-----------------------------------------------------------------*/
4185 /* genPlus - generates code for addition                           */
4186 /*-----------------------------------------------------------------*/
4187 static void
4188 genPlus (iCode * ic)
4189 {
4190   int size, offset = 0;
4191   bool pushResult;
4192   int rSize;
4193
4194   D (emitcode (";", "genPlus "););
4195
4196   /* special cases :- */
4197   if ( AOP_IS_STR(IC_LEFT(ic)) &&
4198       isOperandLiteral(IC_RIGHT(ic)) && OP_SYMBOL(IC_RESULT(ic))->ruonly) {
4199       aopOp (IC_RIGHT (ic), ic, TRUE, FALSE);
4200       size = (int)floatFromVal (AOP (IC_RIGHT(ic))->aopu.aop_lit);
4201       if (size <= 9) {
4202           while (size--) emitcode ("inc","dptr");
4203       } else {
4204           emitcode ("mov","a,dpl");
4205           emitcode ("add","a,#!constbyte",size & 0xff);
4206           emitcode ("mov","dpl,a");
4207           emitcode ("mov","a,dph");
4208           emitcode ("addc","a,#!constbyte",(size >> 8) & 0xff);
4209           emitcode ("mov","dph,a");
4210           emitcode ("mov","a,dpx");
4211           emitcode ("addc","a,#!constbyte",(size >> 16) & 0xff);
4212           emitcode ("mov","dpx,a");
4213       }
4214       freeAsmop (IC_RIGHT (ic), NULL, ic, FALSE);
4215       return ;
4216   }
4217   if ( IS_SYMOP(IC_LEFT(ic)) &&
4218        OP_SYMBOL(IC_LEFT(ic))->remat &&
4219        isOperandInFarSpace(IC_RIGHT(ic))) {
4220       operand *op = IC_RIGHT(ic);
4221       IC_RIGHT(ic) = IC_LEFT(ic);
4222       IC_LEFT(ic) = op;
4223   }
4224
4225   AOP_OP_3_NOFATAL (ic, pushResult);
4226
4227   if (pushResult)
4228     {
4229       D (emitcode (";", "genPlus: must push result: 3 ops in far space"););
4230     }
4231
4232   if (!pushResult)
4233     {
4234       /* if literal, literal on the right or
4235          if left requires ACC or right is already
4236          in ACC */
4237       if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4238        || ((AOP_NEEDSACC (IC_LEFT (ic))) && !(AOP_NEEDSACC (IC_RIGHT (ic))))
4239           || AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
4240         {
4241           operand *t = IC_RIGHT (ic);
4242           IC_RIGHT (ic) = IC_LEFT (ic);
4243           IC_LEFT (ic) = t;
4244           emitcode (";", "Swapped plus args.");
4245         }
4246
4247       /* if both left & right are in bit
4248          space */
4249       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4250           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4251         {
4252           genPlusBits (ic);
4253           goto release;
4254         }
4255
4256       /* if left in bit space & right literal */
4257       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4258           AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
4259         {
4260           emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4261           /* if result in bit space */
4262           if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4263             {
4264               if ((unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit) != 0L)
4265                 emitcode ("cpl", "c");
4266               outBitC (IC_RESULT (ic));
4267             }
4268           else
4269             {
4270               size = getDataSize (IC_RESULT (ic));
4271               _startLazyDPSEvaluation ();
4272               while (size--)
4273                 {
4274                   MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4275                   emitcode ("addc", "a,#0");
4276                   aopPut (AOP (IC_RESULT (ic)), "a", offset++);
4277                 }
4278               _endLazyDPSEvaluation ();
4279             }
4280           goto release;
4281         }
4282
4283       /* if I can do an increment instead
4284          of add then GOOD for ME */
4285       if (genPlusIncr (ic) == TRUE)
4286         {
4287           emitcode (";", "did genPlusIncr");
4288           goto release;
4289         }
4290
4291     }
4292   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4293
4294   _startLazyDPSEvaluation ();
4295   while (size--)
4296     {
4297       if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && !AOP_NEEDSACC(IC_RIGHT(ic)))
4298         {
4299           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4300           if (offset == 0)
4301             emitcode ("add", "a,%s",
4302                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4303           else
4304             emitcode ("addc", "a,%s",
4305                  aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4306         }
4307       else
4308         {
4309           if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC && (offset == 0))
4310           {
4311               /* right is going to use ACC or we would have taken the
4312                * above branch.
4313                */
4314               assert(AOP_NEEDSACC(IC_RIGHT(ic)));
4315        TR_AP("#3");
4316               D(emitcode(";", "+ AOP_ACC special case."););
4317               emitcode("xch", "a, %s", DP2_RESULT_REG);
4318           }
4319           MOVA (aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4320           if (offset == 0)
4321           {
4322             if (AOP_TYPE(IC_LEFT(ic)) == AOP_ACC)
4323             {
4324          TR_AP("#4");
4325                 emitcode("add", "a, %s", DP2_RESULT_REG);
4326             }
4327             else
4328             {
4329                 emitcode ("add", "a,%s",
4330                           aopGet (AOP(IC_LEFT(ic)), offset, FALSE, FALSE,
4331                                   DP2_RESULT_REG));
4332             }
4333           }
4334           else
4335           {
4336             emitcode ("addc", "a,%s",
4337                   aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE,
4338                           DP2_RESULT_REG));
4339           }
4340         }
4341       if (!pushResult)
4342         {
4343           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4344         }
4345       else
4346         {
4347           emitcode ("push", "acc");
4348         }
4349       offset++;
4350     }
4351   _endLazyDPSEvaluation ();
4352
4353   if (pushResult)
4354     {
4355       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4356
4357       size = getDataSize (IC_LEFT (ic));
4358       rSize = getDataSize (IC_RESULT (ic));
4359
4360       ADJUST_PUSHED_RESULT(size, rSize);
4361
4362       _startLazyDPSEvaluation ();
4363       while (size--)
4364         {
4365           emitcode ("pop", "acc");
4366           aopPut (AOP (IC_RESULT (ic)), "a", size);
4367         }
4368       _endLazyDPSEvaluation ();
4369     }
4370
4371   adjustArithmeticResult (ic);
4372
4373 release:
4374   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4375   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4376   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4377 }
4378
4379 /*-----------------------------------------------------------------*/
4380 /* genMinusDec :- does subtraction with deccrement if possible     */
4381 /*-----------------------------------------------------------------*/
4382 static bool
4383 genMinusDec (iCode * ic)
4384 {
4385   unsigned int icount;
4386   unsigned int size = getDataSize (IC_RESULT (ic));
4387
4388   /* will try to generate an increment */
4389   /* if the right side is not a literal
4390      we cannot */
4391   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4392     return FALSE;
4393
4394   /* if the literal value of the right hand side
4395      is greater than 4 then it is not worth it */
4396   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 4)
4397     return FALSE;
4398
4399   if (size == 1 && AOP(IC_LEFT(ic)) == AOP(IC_RESULT(ic)) &&
4400       AOP_TYPE(IC_LEFT(ic)) == AOP_DIR ) {
4401       while (icount--) {
4402           emitcode("dec","%s",aopGet(AOP(IC_RESULT(ic)),0,FALSE,FALSE,NULL));
4403       }
4404       return TRUE;
4405   }
4406   /* if decrement 16 bits in register */
4407   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4408       AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4409       sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
4410       (size > 1) &&
4411       (icount == 1))
4412     {
4413       symbol *tlbl;
4414       int    emitTlbl;
4415       int    labelRange;
4416       char   *l;
4417
4418       /* If the next instruction is a goto and the goto target
4419          * is <= 5 instructions previous to this, we can generate
4420          * jumps straight to that target.
4421        */
4422       if (ic->next && ic->next->op == GOTO
4423           && (labelRange = findLabelBackwards (ic, IC_LABEL (ic->next)->key)) != 0
4424           && labelRange <= 5)
4425         {
4426           emitcode (";", "tail decrement optimized (range %d)", labelRange);
4427           tlbl = IC_LABEL (ic->next);
4428           emitTlbl = 0;
4429         }
4430       else
4431         {
4432           tlbl = newiTempLabel (NULL);
4433           emitTlbl = 1;
4434         }
4435
4436       l = aopGet (AOP (IC_RESULT (ic)), LSB, FALSE, FALSE, NULL);
4437       emitcode ("dec", "%s", l);
4438
4439       if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4440           AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4441           IS_AOP_PREG (IC_RESULT (ic)))
4442       {
4443           emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4444       }
4445       else
4446       {
4447           emitcode ("mov", "a,#!constbyte",0xff);
4448           emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4449       }
4450       l = aopGet (AOP (IC_RESULT (ic)), MSB16, FALSE, FALSE, NULL);
4451       emitcode ("dec", "%s", l);
4452       if (size > 2)
4453         {
4454             if (!strcmp(l, "acc"))
4455             {
4456                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4457             }
4458             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4459                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4460                      IS_AOP_PREG (IC_RESULT (ic)))
4461             {
4462                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4463             }
4464             else
4465             {
4466                 emitcode ("mov", "a,#!constbyte",0xff);
4467                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4468             }
4469             l = aopGet (AOP (IC_RESULT (ic)), MSB24, FALSE, FALSE, NULL);
4470             emitcode ("dec", "%s", l);
4471         }
4472       if (size > 3)
4473         {
4474             if (!strcmp(l, "acc"))
4475             {
4476                 emitcode("jnz", "!tlabel", tlbl->key + 100);
4477             }
4478             else if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG ||
4479                      AOP_TYPE (IC_RESULT (ic)) == AOP_DPTR ||
4480                      IS_AOP_PREG (IC_RESULT (ic)))
4481             {
4482                 emitcode ("cjne", "%s,#!constbyte,!tlabel", l, 0xff, tlbl->key + 100);
4483             }
4484             else
4485             {
4486                 emitcode ("mov", "a,#!constbyte",0xff);
4487                 emitcode ("cjne", "a,%s,!tlabel", l, tlbl->key + 100);
4488             }
4489             l = aopGet (AOP (IC_RESULT (ic)), MSB32, FALSE, FALSE, NULL);
4490             emitcode ("dec", "%s", l);
4491         }
4492       if (emitTlbl)
4493         {
4494           emitcode ("", "!tlabeldef", tlbl->key + 100);
4495         }
4496       return TRUE;
4497     }
4498
4499   /* if the sizes are greater than 1 then we cannot */
4500   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
4501       AOP_SIZE (IC_LEFT (ic)) > 1)
4502     return FALSE;
4503
4504   /* we can if the aops of the left & result match or
4505      if they are in registers and the registers are the
4506      same */
4507   if (
4508        AOP_TYPE (IC_LEFT (ic)) == AOP_REG &&
4509        AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
4510        sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
4511     {
4512
4513       _startLazyDPSEvaluation ();
4514       while (icount--)
4515         {
4516           emitcode ("dec", "%s",
4517                     aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
4518         }
4519       _endLazyDPSEvaluation ();
4520
4521       return TRUE;
4522     }
4523
4524   return FALSE;
4525 }
4526
4527 /*-----------------------------------------------------------------*/
4528 /* addSign - complete with sign                                    */
4529 /*-----------------------------------------------------------------*/
4530 static void
4531 addSign (operand * result, int offset, int sign)
4532 {
4533   int size = (getDataSize (result) - offset);
4534   if (size > 0)
4535     {
4536       _startLazyDPSEvaluation();
4537       if (sign)
4538         {
4539           emitcode ("rlc", "a");
4540           emitcode ("subb", "a,acc");
4541           while (size--)
4542           {
4543             aopPut (AOP (result), "a", offset++);
4544           }
4545         }
4546       else
4547       {
4548         while (size--)
4549         {
4550           aopPut (AOP (result), zero, offset++);
4551         }
4552       }
4553       _endLazyDPSEvaluation();
4554     }
4555 }
4556
4557 /*-----------------------------------------------------------------*/
4558 /* genMinusBits - generates code for subtraction  of two bits      */
4559 /*-----------------------------------------------------------------*/
4560 static void
4561 genMinusBits (iCode * ic)
4562 {
4563   symbol *lbl = newiTempLabel (NULL);
4564
4565   D (emitcode (";", "genMinusBits "););
4566
4567   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY)
4568     {
4569       emitcode ("mov", "c,%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
4570       emitcode ("jnb", "%s,!tlabel", AOP (IC_RIGHT (ic))->aopu.aop_dir, (lbl->key + 100));
4571       emitcode ("cpl", "c");
4572       emitcode ("", "!tlabeldef", (lbl->key + 100));
4573       outBitC (IC_RESULT (ic));
4574     }
4575   else
4576     {
4577       emitcode ("mov", "c,%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
4578       emitcode ("subb", "a,acc");
4579       emitcode ("jnb", "%s,!tlabel", AOP (IC_LEFT (ic))->aopu.aop_dir, (lbl->key + 100));
4580       emitcode ("inc", "a");
4581       emitcode ("", "!tlabeldef", (lbl->key + 100));
4582       aopPut (AOP (IC_RESULT (ic)), "a", 0);
4583       addSign (IC_RESULT (ic), MSB16, SPEC_USIGN (getSpec (operandType (IC_RESULT (ic)))));
4584     }
4585 }
4586
4587 /*-----------------------------------------------------------------*/
4588 /* genMinus - generates code for subtraction                       */
4589 /*-----------------------------------------------------------------*/
4590 static void
4591 genMinus (iCode * ic)
4592 {
4593     int size, offset = 0;
4594     int rSize;
4595     long lit = 0L;
4596     bool pushResult;
4597
4598     D (emitcode (";", "genMinus "););
4599
4600     AOP_OP_3_NOFATAL(ic, pushResult);
4601
4602     if (!pushResult)
4603     {
4604       /* special cases :- */
4605       /* if both left & right are in bit space */
4606       if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
4607           AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
4608         {
4609           genMinusBits (ic);
4610           goto release;
4611         }
4612
4613       /* if I can do an decrement instead
4614          of subtract then GOOD for ME */
4615       if (genMinusDec (ic) == TRUE)
4616         goto release;
4617
4618     }
4619
4620   size = getDataSize (pushResult ? IC_LEFT (ic) : IC_RESULT (ic));
4621
4622   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
4623     {
4624       CLRC;
4625     }
4626   else
4627     {
4628       lit = (long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
4629       lit = -lit;
4630     }
4631
4632
4633   /* if literal, add a,#-lit, else normal subb */
4634   _startLazyDPSEvaluation ();
4635   while (size--) {
4636       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT) {
4637           if (AOP_USESDPTR(IC_RIGHT(ic))) {
4638               emitcode ("mov","b,%s",
4639                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE, NULL));
4640               MOVA(aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4641               emitcode ("subb","a,b");
4642           } else {
4643               MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4644               emitcode ("subb", "a,%s",
4645                         aopGet (AOP (IC_RIGHT (ic)), offset, FALSE, FALSE,
4646                                 DP2_RESULT_REG));
4647           }
4648       } else {
4649           MOVA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE, FALSE, NULL));
4650           /* first add without previous c */
4651           if (!offset) {
4652               if (!size && lit==-1) {
4653                   emitcode ("dec", "a");
4654               } else {
4655                   emitcode ("add", "a,#!constbyte",
4656                             (unsigned int) (lit & 0x0FFL));
4657               }
4658           } else {
4659               emitcode ("addc", "a,#!constbyte",
4660                         (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
4661           }
4662       }
4663
4664       if (pushResult) {
4665           emitcode ("push", "acc");
4666       } else {
4667           aopPut (AOP (IC_RESULT (ic)), "a", offset);
4668       }
4669       offset++;
4670   }
4671   _endLazyDPSEvaluation ();
4672
4673   if (pushResult)
4674     {
4675       aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
4676
4677       size = getDataSize (IC_LEFT (ic));
4678       rSize = getDataSize (IC_RESULT (ic));
4679
4680       ADJUST_PUSHED_RESULT(size, rSize);
4681
4682       _startLazyDPSEvaluation ();
4683       while (size--)
4684         {
4685           emitcode ("pop", "acc");
4686           aopPut (AOP (IC_RESULT (ic)), "a", size);
4687         }
4688       _endLazyDPSEvaluation ();
4689     }
4690
4691   adjustArithmeticResult (ic);
4692
4693 release:
4694   freeAsmop (IC_LEFT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4695   freeAsmop (IC_RIGHT (ic), NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
4696   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
4697 }
4698
4699
4700 /*-----------------------------------------------------------------*/
4701 /* genMultbits :- multiplication of bits                           */
4702 /*-----------------------------------------------------------------*/
4703 static void
4704 genMultbits (operand * left,
4705              operand * right,
4706              operand * result,
4707              iCode   * ic)
4708 {
4709   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
4710   emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
4711   aopOp(result, ic, TRUE, FALSE);
4712   outBitC (result);
4713 }
4714
4715
4716 /*-----------------------------------------------------------------*/
4717 /* genMultOneByte : 8*8=8/16 bit multiplication                    */
4718 /*-----------------------------------------------------------------*/
4719 static void
4720 genMultOneByte (operand * left,
4721                 operand * right,
4722                 operand * result,
4723                 iCode   * ic)
4724 {
4725   int size;
4726   symbol *lbl;
4727   bool runtimeSign, compiletimeSign;
4728   bool lUnsigned, rUnsigned;
4729
4730
4731   /* (if two literals: the value is computed before) */
4732   /* if one literal, literal on the right */
4733   if (AOP_TYPE (left) == AOP_LIT)
4734     {
4735       operand *t = right;
4736       right = left;
4737       left = t;
4738       emitcode (";", "swapped left and right");
4739     }
4740
4741   /* (if two literals: the value is computed before) */
4742   /* if one literal, literal on the right */
4743   if (AOP_TYPE (left) == AOP_LIT)
4744     {
4745       operand *t = right;
4746       right = left;
4747       left = t;
4748       /* emitcode (";", "swapped left and right"); */
4749     }
4750   /* if no literal, unsigned on the right: shorter code */
4751   if (   AOP_TYPE (right) != AOP_LIT
4752       && SPEC_USIGN (getSpec (operandType (left))))
4753     {
4754       operand *t = right;
4755       right = left;
4756       left = t;
4757     }
4758
4759   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
4760   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
4761
4762   if ((lUnsigned && rUnsigned)
4763 /* sorry, I don't know how to get size
4764    without calling aopOp (result,...);
4765    see Feature Request  */
4766       /* || size == 1 */ ) /* no, this is not a bug; with a 1 byte result there's
4767                    no need to take care about the signedness! */
4768     {
4769       /* just an unsigned 8 * 8 = 8 multiply
4770          or 8u * 8u = 16u */
4771       /* emitcode (";","unsigned"); */
4772       emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4773       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4774       emitcode ("mul", "ab");
4775
4776       _G.accInUse++; _G.bInUse++;
4777       aopOp (result, ic, TRUE, FALSE);
4778       size = AOP_SIZE (result);
4779
4780       if (size < 1 || size > 2)
4781         {
4782           /* this should never happen */
4783           fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4784                    size, __FILE__, lineno);
4785           exit (1);
4786         }
4787
4788       aopPut (AOP (result), "a", 0);
4789       _G.accInUse--; _G.bInUse--;
4790       if (size == 2)
4791         aopPut (AOP (result), "b", 1);
4792       return;
4793     }
4794
4795   /* we have to do a signed multiply */
4796   /* emitcode (";", "signed"); */
4797
4798   /* now sign adjust for both left & right */
4799
4800   /* let's see what's needed: */
4801   /* apply negative sign during runtime */
4802   runtimeSign = FALSE;
4803   /* negative sign from literals */
4804   compiletimeSign = FALSE;
4805
4806   if (!lUnsigned)
4807     {
4808       if (AOP_TYPE(left) == AOP_LIT)
4809         {
4810           /* signed literal */
4811           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4812           if (val < 0)
4813             compiletimeSign = TRUE;
4814         }
4815       else
4816         /* signed but not literal */
4817         runtimeSign = TRUE;
4818     }
4819
4820   if (!rUnsigned)
4821     {
4822       if (AOP_TYPE(right) == AOP_LIT)
4823         {
4824           /* signed literal */
4825           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4826           if (val < 0)
4827             compiletimeSign ^= TRUE;
4828         }
4829       else
4830         /* signed but not literal */
4831         runtimeSign = TRUE;
4832     }
4833
4834   /* initialize F0, which stores the runtime sign */
4835   if (runtimeSign)
4836     {
4837       if (compiletimeSign)
4838         emitcode ("setb", "F0"); /* set sign flag */
4839       else
4840         emitcode ("clr", "F0"); /* reset sign flag */
4841     }
4842
4843   /* save the signs of the operands */
4844   if (AOP_TYPE(right) == AOP_LIT)
4845     {
4846       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
4847
4848       if (!rUnsigned && val < 0)
4849         emitcode ("mov", "b,#!constbyte", -val);
4850       else
4851         emitcode ("mov", "b,#!constbyte", (unsigned char) val);
4852     }
4853   else /* ! literal */
4854     {
4855       if (rUnsigned)  /* emitcode (";", "signed"); */
4856         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4857       else
4858         {
4859           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
4860           lbl = newiTempLabel (NULL);
4861           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
4862           emitcode ("cpl", "F0"); /* complement sign flag */
4863           emitcode ("cpl", "a");  /* 2's complement */
4864           emitcode ("inc", "a");
4865           emitcode ("", "!tlabeldef", lbl->key + 100);
4866           emitcode ("mov", "b,a");
4867         }
4868     }
4869
4870   if (AOP_TYPE(left) == AOP_LIT)
4871     {
4872       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
4873
4874       if (!lUnsigned && val < 0)
4875         emitcode ("mov", "a,#!constbyte", -val);
4876       else
4877         emitcode ("mov", "a,#!constbyte", (unsigned char) val);
4878     }
4879   else /* ! literal */
4880     {
4881       if (lUnsigned)  /* emitcode (";", "signed"); */
4882
4883         emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4884       else
4885         {
4886           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
4887           lbl = newiTempLabel (NULL);
4888           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
4889           emitcode ("cpl", "F0"); /* complement sign flag */
4890           emitcode ("cpl", "a");  /* 2's complement */
4891           emitcode ("inc", "a");
4892           emitcode ("", "!tlabeldef", lbl->key + 100);
4893         }
4894     }
4895
4896   /* now the multiplication */
4897   emitcode ("mul", "ab");
4898   _G.accInUse++;_G.bInUse++;
4899   aopOp(result, ic, TRUE, FALSE);
4900   size = AOP_SIZE (result);
4901
4902   if (size < 1 || size > 2)
4903     {
4904       /* this should never happen */
4905       fprintf (stderr, "size!=1||2 (%d) in %s at line:%d \n",
4906                size, __FILE__, lineno);
4907       exit (1);
4908     }
4909
4910   if (runtimeSign || compiletimeSign)
4911     {
4912       lbl = newiTempLabel (NULL);
4913       if (runtimeSign)
4914         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
4915       emitcode ("cpl", "a"); /* lsb 2's complement */
4916       if (size != 2)
4917         emitcode ("inc", "a"); /* inc doesn't set carry flag */
4918       else
4919         {
4920           emitcode ("add", "a,#1"); /* this sets carry flag */
4921           emitcode ("xch", "a,b");
4922           emitcode ("cpl", "a"); /* msb 2's complement */
4923           emitcode ("addc", "a,#0");
4924           emitcode ("xch", "a,b");
4925         }
4926       emitcode ("", "!tlabeldef", lbl->key + 100);
4927     }
4928   aopPut (AOP (result), "a", 0);
4929   _G.accInUse--;_G.bInUse--;
4930   if (size == 2)
4931     aopPut (AOP (result), "b", 1);
4932 }
4933
4934 /*-----------------------------------------------------------------*/
4935 /* genMultTwoByte - use the DS390 MAC unit to do 16*16 multiply    */
4936 /*-----------------------------------------------------------------*/
4937 static void genMultTwoByte (operand *left, operand *right,
4938                             operand *result, iCode *ic)
4939 {
4940         sym_link *retype = getSpec(operandType(right));
4941         sym_link *letype = getSpec(operandType(left));
4942         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
4943         symbol *lbl;
4944
4945         if (AOP_TYPE (left) == AOP_LIT) {
4946                 operand *t = right;
4947                 right = left;
4948                 left = t;
4949         }
4950         /* save EA bit in F1 */
4951         lbl = newiTempLabel(NULL);
4952         emitcode ("setb","F1");
4953         emitcode ("jbc","EA,!tlabel",lbl->key+100);
4954         emitcode ("clr","F1");
4955         emitcode("","!tlabeldef",lbl->key+100);
4956
4957         /* load up MB with right */
4958         if (!umult) {
4959                 emitcode("clr","F0");
4960                 if (AOP_TYPE(right) == AOP_LIT) {
4961                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
4962                         if (val < 0) {
4963                                 emitcode("setb","F0");
4964                                 val = -val;
4965                         }
4966                         emitcode ("mov","mb,#!constbyte",val & 0xff);
4967                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
4968                 } else {
4969                         lbl = newiTempLabel(NULL);
4970                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4971                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4972                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4973                         emitcode ("xch", "a,b");
4974                         emitcode ("cpl","a");
4975                         emitcode ("add", "a,#1");
4976                         emitcode ("xch", "a,b");
4977                         emitcode ("cpl", "a"); // msb
4978                         emitcode ("addc", "a,#0");
4979                         emitcode ("setb","F0");
4980                         emitcode ("","!tlabeldef",lbl->key+100);
4981                         emitcode ("mov","mb,b");
4982                         emitcode ("mov","mb,a");
4983                 }
4984         } else {
4985                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
4986                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
4987         }
4988         /* load up MA with left */
4989         if (!umult) {
4990                 lbl = newiTempLabel(NULL);
4991                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
4992                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
4993                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
4994                 emitcode ("xch", "a,b");
4995                 emitcode ("cpl","a");
4996                 emitcode ("add", "a,#1");
4997                 emitcode ("xch", "a,b");
4998                 emitcode ("cpl", "a"); // msb
4999                 emitcode ("addc","a,#0");
5000                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5001                 emitcode ("setb","F0");
5002                 emitcode ("","!tlabeldef",lbl->key+100);
5003                 emitcode ("mov","ma,b");
5004                 emitcode ("mov","ma,a");
5005         } else {
5006                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5007                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5008         }
5009         /* wait for multiplication to finish */
5010         lbl = newiTempLabel(NULL);
5011         emitcode("","!tlabeldef", lbl->key+100);
5012         emitcode("mov","a,mcnt1");
5013         emitcode("anl","a,#!constbyte",0x80);
5014         emitcode("jnz","!tlabel",lbl->key+100);
5015
5016         freeAsmop (left, NULL, ic, TRUE);
5017         freeAsmop (right, NULL, ic,TRUE);
5018         aopOp(result, ic, TRUE, FALSE);
5019
5020         /* if unsigned then simple */
5021         if (umult) {
5022                 emitcode ("mov","a,ma");
5023                 if (AOP_SIZE(result) >= 4) aopPut(AOP(result),"a",3);
5024                 emitcode ("mov","a,ma");
5025                 if (AOP_SIZE(result) >= 3) aopPut(AOP(result),"a",2);
5026                 aopPut(AOP(result),"ma",1);
5027                 aopPut(AOP(result),"ma",0);
5028         } else {
5029                 emitcode("push","ma");
5030                 emitcode("push","ma");
5031                 emitcode("push","ma");
5032                 MOVA("ma");
5033                 /* negate result if needed */
5034                 lbl = newiTempLabel(NULL);
5035                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5036                 emitcode("cpl","a");
5037                 emitcode("add","a,#1");
5038                 emitcode("","!tlabeldef", lbl->key+100);
5039                 if (AOP_TYPE(result) == AOP_ACC)
5040                 {
5041                     D(emitcode(";", "ACC special case."););
5042                     /* We know result is the only live aop, and
5043                      * it's obviously not a DPTR2, so AP is available.
5044                      */
5045                     emitcode("mov", "%s,acc", DP2_RESULT_REG);
5046                 }
5047                 else
5048                 {
5049                     aopPut(AOP(result),"a",0);
5050                 }
5051
5052                 emitcode("pop","acc");
5053                 lbl = newiTempLabel(NULL);
5054                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5055                 emitcode("cpl","a");
5056                 emitcode("addc","a,#0");
5057                 emitcode("","!tlabeldef", lbl->key+100);
5058                 aopPut(AOP(result),"a",1);
5059                 emitcode("pop","acc");
5060                 if (AOP_SIZE(result) >= 3) {
5061                         lbl = newiTempLabel(NULL);
5062                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5063                         emitcode("cpl","a");
5064                         emitcode("addc","a,#0");
5065                         emitcode("","!tlabeldef", lbl->key+100);
5066                         aopPut(AOP(result),"a",2);
5067                 }
5068                 emitcode("pop","acc");
5069                 if (AOP_SIZE(result) >= 4) {
5070                         lbl = newiTempLabel(NULL);
5071                         emitcode("jnb","F0,!tlabel",lbl->key+100);
5072                         emitcode("cpl","a");
5073                         emitcode("addc","a,#0");
5074                         emitcode("","!tlabeldef", lbl->key+100);
5075                         aopPut(AOP(result),"a",3);
5076                 }
5077                 if (AOP_TYPE(result) == AOP_ACC)
5078                 {
5079                     /* We stashed the result away above. */
5080                     emitcode("mov", "acc,%s", DP2_RESULT_REG);
5081                 }
5082
5083         }
5084         freeAsmop (result, NULL, ic, TRUE);
5085
5086         /* restore EA bit in F1 */
5087         lbl = newiTempLabel(NULL);
5088         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5089         emitcode ("setb","EA");
5090         emitcode("","!tlabeldef",lbl->key+100);
5091         return ;
5092 }
5093
5094 /*-----------------------------------------------------------------*/
5095 /* genMult - generates code for multiplication                     */
5096 /*-----------------------------------------------------------------*/
5097 static void
5098 genMult (iCode * ic)
5099 {
5100   operand *left = IC_LEFT (ic);
5101   operand *right = IC_RIGHT (ic);
5102   operand *result = IC_RESULT (ic);
5103
5104   D (emitcode (";", "genMult "););
5105
5106   /* assign the amsops */
5107   AOP_OP_2 (ic);
5108
5109   /* special cases first */
5110   /* both are bits */
5111   if (AOP_TYPE (left) == AOP_CRY &&
5112       AOP_TYPE (right) == AOP_CRY)
5113     {
5114       genMultbits (left, right, result, ic);
5115       goto release;
5116     }
5117
5118   /* if both are of size == 1 */
5119   if (AOP_SIZE (left) == 1 &&
5120       AOP_SIZE (right) == 1)
5121     {
5122       genMultOneByte (left, right, result, ic);
5123       goto release;
5124     }
5125
5126   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5127           /* use the ds390 ARITHMETIC accel UNIT */
5128           genMultTwoByte (left, right, result, ic);
5129           return ;
5130   }
5131   /* should have been converted to function call */
5132   assert (0);
5133
5134 release:
5135   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5136   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5137   freeAsmop (result, NULL, ic, TRUE);
5138 }
5139
5140 /*-----------------------------------------------------------------*/
5141 /* genDivbits :- division of bits                                  */
5142 /*-----------------------------------------------------------------*/
5143 static void
5144 genDivbits (operand * left,
5145             operand * right,
5146             operand * result,
5147             iCode   * ic)
5148 {
5149
5150   char *l;
5151
5152   /* the result must be bit */
5153   LOAD_AB_FOR_DIV (left, right, l);
5154   emitcode ("div", "ab");
5155   emitcode ("rrc", "a");
5156   aopOp(result, ic, TRUE, FALSE);
5157
5158   aopPut (AOP (result), "c", 0);
5159 }
5160
5161 /*-----------------------------------------------------------------*/
5162 /* genDivOneByte : 8 bit division                                  */
5163 /*-----------------------------------------------------------------*/
5164 static void
5165 genDivOneByte (operand * left,
5166                operand * right,
5167                operand * result,
5168                iCode   * ic)
5169 {
5170   bool lUnsigned, rUnsigned;
5171   bool runtimeSign, compiletimeSign;
5172   char *l;
5173   symbol *lbl;
5174   int size, offset;
5175
5176   offset = 1;
5177   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5178   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5179
5180   /* signed or unsigned */
5181   if (lUnsigned && rUnsigned)
5182     {
5183       /* unsigned is easy */
5184       LOAD_AB_FOR_DIV (left, right, l);
5185       emitcode ("div", "ab");
5186
5187       _G.accInUse++;
5188       aopOp (result, ic, TRUE, FALSE);
5189       aopPut (AOP (result), "a", 0);
5190       _G.accInUse--;
5191
5192       size = AOP_SIZE (result) - 1;
5193
5194       while (size--)
5195         aopPut (AOP (result), zero, offset++);
5196       return;
5197     }
5198
5199   /* signed is a little bit more difficult */
5200
5201   /* now sign adjust for both left & right */
5202
5203   /* let's see what's needed: */
5204   /* apply negative sign during runtime */
5205   runtimeSign = FALSE;
5206   /* negative sign from literals */
5207   compiletimeSign = FALSE;
5208
5209   if (!lUnsigned)
5210     {
5211       if (AOP_TYPE(left) == AOP_LIT)
5212         {
5213           /* signed literal */
5214           signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5215           if (val < 0)
5216             compiletimeSign = TRUE;
5217         }
5218       else
5219         /* signed but not literal */
5220         runtimeSign = TRUE;
5221     }
5222
5223   if (!rUnsigned)
5224     {
5225       if (AOP_TYPE(right) == AOP_LIT)
5226         {
5227           /* signed literal */
5228           signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5229           if (val < 0)
5230             compiletimeSign ^= TRUE;
5231         }
5232       else
5233         /* signed but not literal */
5234         runtimeSign = TRUE;
5235     }
5236
5237   /* initialize F0, which stores the runtime sign */
5238   if (runtimeSign)
5239     {
5240       if (compiletimeSign)
5241         emitcode ("setb", "F0"); /* set sign flag */
5242       else
5243         emitcode ("clr", "F0"); /* reset sign flag */
5244     }
5245
5246   /* save the signs of the operands */
5247   if (AOP_TYPE(right) == AOP_LIT)
5248     {
5249       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5250
5251       if (!rUnsigned && val < 0)
5252         emitcode ("mov", "b,#0x%02x", -val);
5253       else
5254         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5255     }
5256   else /* ! literal */
5257     {
5258       if (rUnsigned)
5259         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5260       else
5261         {
5262           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5263           lbl = newiTempLabel (NULL);
5264           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5265           emitcode ("cpl", "F0"); /* complement sign flag */
5266           emitcode ("cpl", "a");  /* 2's complement */
5267           emitcode ("inc", "a");
5268           emitcode ("", "!tlabeldef", lbl->key + 100);
5269           emitcode ("mov", "b,a");
5270         }
5271     }
5272
5273   if (AOP_TYPE(left) == AOP_LIT)
5274     {
5275       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5276
5277       if (!lUnsigned && val < 0)
5278         emitcode ("mov", "a,#0x%02x", -val);
5279       else
5280         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5281     }
5282   else /* ! literal */
5283     {
5284       if (lUnsigned)
5285         emitcode ("mov", "a,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5286       else
5287         {
5288           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5289           lbl = newiTempLabel (NULL);
5290           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5291           emitcode ("cpl", "F0"); /* complement sign flag */
5292           emitcode ("cpl", "a");  /* 2's complement */
5293           emitcode ("inc", "a");
5294           emitcode ("", "!tlabeldef", lbl->key + 100);
5295         }
5296     }
5297
5298   /* now the division */
5299   emitcode ("nop", "; workaround for DS80C390 div bug.");
5300   emitcode ("div", "ab");
5301
5302   if (runtimeSign || compiletimeSign)
5303     {
5304       lbl = newiTempLabel (NULL);
5305       if (runtimeSign)
5306         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5307       emitcode ("cpl", "a"); /* lsb 2's complement */
5308       emitcode ("inc", "a");
5309       emitcode ("", "!tlabeldef", lbl->key + 100);
5310
5311       _G.accInUse++;     _G.bInUse++;
5312       aopOp (result, ic, TRUE, FALSE);
5313       size = AOP_SIZE (result) - 1;
5314
5315       if (size > 0)
5316         {
5317           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5318              then the result will be in b, a */
5319           emitcode ("mov", "b,a"); /* 1 */
5320           /* msb is 0x00 or 0xff depending on the sign */
5321           if (runtimeSign)
5322             {
5323               emitcode ("mov",  "c,F0");
5324               emitcode ("subb", "a,acc");
5325               emitcode ("xch",  "a,b"); /* 2 */
5326               while (size--)
5327                 aopPut (AOP (result), "b", offset++); /* write msb's */
5328             }
5329           else /* compiletimeSign */
5330             while (size--)
5331               aopPut (AOP (result), "#0xff", offset++); /* write msb's */
5332         }
5333       aopPut (AOP (result), "a", 0); /* 3: write lsb */
5334     }
5335   else
5336     {
5337       _G.accInUse++;     _G.bInUse++;
5338       aopOp(result, ic, TRUE, FALSE);
5339       size = AOP_SIZE (result) - 1;
5340
5341       aopPut (AOP (result), "a", 0);
5342       while (size--)
5343         aopPut (AOP (result), zero, offset++);
5344     }
5345   _G.accInUse--;     _G.bInUse--;
5346
5347 }
5348
5349 /*-----------------------------------------------------------------*/
5350 /* genDivTwoByte - use the DS390 MAC unit to do 16/16 divide       */
5351 /*-----------------------------------------------------------------*/
5352 static void genDivTwoByte (operand *left, operand *right,
5353                             operand *result, iCode *ic)
5354 {
5355         sym_link *retype = getSpec(operandType(right));
5356         sym_link *letype = getSpec(operandType(left));
5357         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5358         symbol *lbl;
5359
5360         /* save EA bit in F1 */
5361         lbl = newiTempLabel(NULL);
5362         emitcode ("setb","F1");
5363         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5364         emitcode ("clr","F1");
5365         emitcode("","!tlabeldef",lbl->key+100);
5366
5367         /* load up MA with left */
5368         if (!umult) {
5369                 emitcode("clr","F0");
5370                 lbl = newiTempLabel(NULL);
5371                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5372                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5373                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5374                 emitcode ("xch", "a,b");
5375                 emitcode ("cpl","a");
5376                 emitcode ("add", "a,#1");
5377                 emitcode ("xch", "a,b");
5378                 emitcode ("cpl", "a"); // msb
5379                 emitcode ("addc","a,#0");
5380                 emitcode ("setb","F0");
5381                 emitcode ("","!tlabeldef",lbl->key+100);
5382                 emitcode ("mov","ma,b");
5383                 emitcode ("mov","ma,a");
5384         } else {
5385                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5386                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5387         }
5388
5389         /* load up MB with right */
5390         if (!umult) {
5391                 if (AOP_TYPE(right) == AOP_LIT) {
5392                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5393                         if (val < 0) {
5394                                 lbl = newiTempLabel(NULL);
5395                                 emitcode ("jbc","F0,!tlabel",lbl->key+100);
5396                                 emitcode("setb","F0");
5397                                 emitcode ("","!tlabeldef",lbl->key+100);
5398                                 val = -val;
5399                         }
5400                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5401                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5402                 } else {
5403                         lbl = newiTempLabel(NULL);
5404                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5405                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5406                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5407                         emitcode ("xch", "a,b");
5408                         emitcode ("cpl","a");
5409                         emitcode ("add", "a,#1");
5410                         emitcode ("xch", "a,b");
5411                         emitcode ("cpl", "a"); // msb
5412                         emitcode ("addc", "a,#0");
5413                         emitcode ("jbc","F0,!tlabel",lbl->key+100);
5414                         emitcode ("setb","F0");
5415                         emitcode ("","!tlabeldef",lbl->key+100);
5416                         emitcode ("mov","mb,b");
5417                         emitcode ("mov","mb,a");
5418                 }
5419         } else {
5420                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5421                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5422         }
5423
5424         /* wait for multiplication to finish */
5425         lbl = newiTempLabel(NULL);
5426         emitcode("","!tlabeldef", lbl->key+100);
5427         emitcode("mov","a,mcnt1");
5428         emitcode("anl","a,#!constbyte",0x80);
5429         emitcode("jnz","!tlabel",lbl->key+100);
5430
5431         freeAsmop (left, NULL, ic, TRUE);
5432         freeAsmop (right, NULL, ic,TRUE);
5433         aopOp(result, ic, TRUE, FALSE);
5434
5435         /* if unsigned then simple */
5436         if (umult) {
5437                 aopPut(AOP(result),"ma",1);
5438                 aopPut(AOP(result),"ma",0);
5439         } else {
5440                 emitcode("push","ma");
5441                 MOVA("ma");
5442                 /* negate result if needed */
5443                 lbl = newiTempLabel(NULL);
5444                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5445                 emitcode("cpl","a");
5446                 emitcode("add","a,#1");
5447                 emitcode("","!tlabeldef", lbl->key+100);
5448                 aopPut(AOP(result),"a",0);
5449                 emitcode("pop","acc");
5450                 lbl = newiTempLabel(NULL);
5451                 emitcode("jnb","F0,!tlabel",lbl->key+100);
5452                 emitcode("cpl","a");
5453                 emitcode("addc","a,#0");
5454                 emitcode("","!tlabeldef", lbl->key+100);
5455                 aopPut(AOP(result),"a",1);
5456         }
5457         freeAsmop (result, NULL, ic, TRUE);
5458         /* restore EA bit in F1 */
5459         lbl = newiTempLabel(NULL);
5460         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5461         emitcode ("setb","EA");
5462         emitcode("","!tlabeldef",lbl->key+100);
5463         return ;
5464 }
5465
5466 /*-----------------------------------------------------------------*/
5467 /* genDiv - generates code for division                            */
5468 /*-----------------------------------------------------------------*/
5469 static void
5470 genDiv (iCode * ic)
5471 {
5472   operand *left = IC_LEFT (ic);
5473   operand *right = IC_RIGHT (ic);
5474   operand *result = IC_RESULT (ic);
5475
5476   D (emitcode (";", "genDiv "););
5477
5478   /* assign the amsops */
5479   AOP_OP_2 (ic);
5480
5481   /* special cases first */
5482   /* both are bits */
5483   if (AOP_TYPE (left) == AOP_CRY &&
5484       AOP_TYPE (right) == AOP_CRY)
5485     {
5486       genDivbits (left, right, result, ic);
5487       goto release;
5488     }
5489
5490   /* if both are of size == 1 */
5491   if (AOP_SIZE (left) == 1 &&
5492       AOP_SIZE (right) == 1)
5493     {
5494       genDivOneByte (left, right, result, ic);
5495       goto release;
5496     }
5497
5498   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5499           /* use the ds390 ARITHMETIC accel UNIT */
5500           genDivTwoByte (left, right, result, ic);
5501           return ;
5502   }
5503   /* should have been converted to function call */
5504   assert (0);
5505 release:
5506   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5507   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5508   freeAsmop (result, NULL, ic, TRUE);
5509 }
5510
5511 /*-----------------------------------------------------------------*/
5512 /* genModbits :- modulus of bits                                   */
5513 /*-----------------------------------------------------------------*/
5514 static void
5515 genModbits (operand * left,
5516             operand * right,
5517             operand * result,
5518             iCode   * ic)
5519 {
5520
5521   char *l;
5522
5523   /* the result must be bit */
5524   LOAD_AB_FOR_DIV (left, right, l);
5525   emitcode ("div", "ab");
5526   emitcode ("mov", "a,b");
5527   emitcode ("rrc", "a");
5528   aopOp(result, ic, TRUE, FALSE);
5529   aopPut (AOP (result), "c", 0);
5530 }
5531
5532 /*-----------------------------------------------------------------*/
5533 /* genModOneByte : 8 bit modulus                                   */
5534 /*-----------------------------------------------------------------*/
5535 static void
5536 genModOneByte (operand * left,
5537                operand * right,
5538                operand * result,
5539                iCode   * ic)
5540 {
5541   bool lUnsigned, rUnsigned;
5542   bool runtimeSign, compiletimeSign;
5543   char *l;
5544   symbol *lbl;
5545   int size, offset;
5546
5547   offset = 1;
5548   lUnsigned = SPEC_USIGN (getSpec (operandType (left)));
5549   rUnsigned = SPEC_USIGN (getSpec (operandType (right)));
5550
5551   /* signed or unsigned */
5552   if (lUnsigned && rUnsigned)
5553     {
5554       /* unsigned is easy */
5555       LOAD_AB_FOR_DIV (left, right, l);
5556       emitcode ("div", "ab");
5557       aopOp (result, ic, TRUE, FALSE);
5558       aopPut (AOP (result), "b", 0);
5559
5560       for (size = AOP_SIZE (result) - 1; size--;)
5561         aopPut (AOP (result), zero, offset++);
5562       return;
5563     }
5564
5565   /* signed is a little bit more difficult */
5566
5567   /* now sign adjust for both left & right */
5568
5569   /* modulus: sign of the right operand has no influence on the result! */
5570   if (AOP_TYPE(right) == AOP_LIT)
5571     {
5572       signed char val = (char) floatFromVal (AOP (right)->aopu.aop_lit);
5573
5574       if (!rUnsigned && val < 0)
5575         emitcode ("mov", "b,#0x%02x", -val);
5576       else
5577         emitcode ("mov", "b,#0x%02x", (unsigned char) val);
5578     }
5579   else /* ! literal */
5580     {
5581       if (rUnsigned)
5582         emitcode ("mov", "b,%s", aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5583       else
5584         {
5585           MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
5586           lbl = newiTempLabel (NULL);
5587           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5588           emitcode ("cpl", "a");  /* 2's complement */
5589           emitcode ("inc", "a");
5590           emitcode ("", "!tlabeldef", lbl->key + 100);
5591           emitcode ("mov", "b,a");
5592         }
5593     }
5594
5595   /* let's see what's needed: */
5596   /* apply negative sign during runtime */
5597   runtimeSign = FALSE;
5598   /* negative sign from literals */
5599   compiletimeSign = FALSE;
5600
5601   /* sign adjust left side */
5602   if (AOP_TYPE(left) == AOP_LIT)
5603     {
5604       signed char val = (char) floatFromVal (AOP (left)->aopu.aop_lit);
5605
5606       if (!lUnsigned && val < 0)
5607         {
5608           compiletimeSign = TRUE; /* set sign flag */
5609           emitcode ("mov", "a,#0x%02x", -val);
5610         }
5611       else
5612         emitcode ("mov", "a,#0x%02x", (unsigned char) val);
5613     }
5614   else /* ! literal */
5615     {
5616       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
5617
5618       if (!lUnsigned)
5619         {
5620           runtimeSign = TRUE;
5621           emitcode ("clr", "F0"); /* clear sign flag */
5622
5623           lbl = newiTempLabel (NULL);
5624           emitcode ("jnb", "acc.7,!tlabel", lbl->key + 100);
5625           emitcode ("setb", "F0"); /* set sign flag */
5626           emitcode ("cpl", "a");   /* 2's complement */
5627           emitcode ("inc", "a");
5628           emitcode ("", "!tlabeldef", lbl->key + 100);
5629         }
5630     }
5631
5632   /* now the modulus */
5633   emitcode ("nop", "; workaround for DS80C390 div bug.");
5634   emitcode ("div", "ab");
5635
5636   if (runtimeSign || compiletimeSign)
5637     {
5638       emitcode ("mov", "a,b");
5639       lbl = newiTempLabel (NULL);
5640       if (runtimeSign)
5641         emitcode ("jnb", "F0,!tlabel", lbl->key + 100);
5642       emitcode ("cpl", "a"); /* lsb 2's complement */
5643       emitcode ("inc", "a");
5644       emitcode ("", "!tlabeldef", lbl->key + 100);
5645
5646       _G.accInUse++;     _G.bInUse++;
5647       aopOp (result, ic, TRUE, FALSE);
5648       size = AOP_SIZE (result) - 1;
5649
5650       if (size > 0)
5651         {
5652           /* 123 look strange, but if (OP_SYMBOL (op)->accuse == 1)
5653              then the result will be in b, a */
5654           emitcode ("mov", "b,a"); /* 1 */
5655           /* msb is 0x00 or 0xff depending on the sign */
5656           if (runtimeSign)
5657             {
5658               emitcode ("mov",  "c,F0");
5659               emitcode ("subb", "a,acc");
5660               emitcode ("xch",  "a,b"); /* 2 */
5661               while (size--)
5662                 aopPut (AOP (result), "b", offset++); /* write msb's */
5663             }
5664           else /* compiletimeSign */
5665             while (size--)
5666               aopPut (AOP (result), "#0xff", offset++); /* write msb's */
5667         }
5668       aopPut (AOP (result), "a", 0); /* 3: write lsb */
5669     }
5670   else
5671     {
5672       _G.accInUse++;     _G.bInUse++;
5673       aopOp(result, ic, TRUE, FALSE);
5674       size = AOP_SIZE (result) - 1;
5675
5676       aopPut (AOP (result), "b", 0);
5677       while (size--)
5678         aopPut (AOP (result), zero, offset++);
5679     }
5680   _G.accInUse--;     _G.bInUse--;
5681
5682 }
5683
5684 /*-----------------------------------------------------------------*/
5685 /* genModTwoByte - use the DS390 MAC unit to do 16%16 modulus      */
5686 /*-----------------------------------------------------------------*/
5687 static void genModTwoByte (operand *left, operand *right,
5688                             operand *result, iCode *ic)
5689 {
5690         sym_link *retype = getSpec(operandType(right));
5691         sym_link *letype = getSpec(operandType(left));
5692         int umult = SPEC_USIGN(retype) | SPEC_USIGN(letype);
5693         symbol *lbl;
5694
5695         /* load up MA with left */
5696         /* save EA bit in F1 */
5697         lbl = newiTempLabel(NULL);
5698         emitcode ("setb","F1");
5699         emitcode ("jbc","EA,!tlabel",lbl->key+100);
5700         emitcode ("clr","F1");
5701         emitcode("","!tlabeldef",lbl->key+100);
5702
5703         if (!umult) {
5704                 lbl = newiTempLabel(NULL);
5705                 emitcode ("mov","b,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5706                 emitcode ("mov","a,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5707                 emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5708                 emitcode ("xch", "a,b");
5709                 emitcode ("cpl","a");
5710                 emitcode ("add", "a,#1");
5711                 emitcode ("xch", "a,b");
5712                 emitcode ("cpl", "a"); // msb
5713                 emitcode ("addc","a,#0");
5714                 emitcode ("","!tlabeldef",lbl->key+100);
5715                 emitcode ("mov","ma,b");
5716                 emitcode ("mov","ma,a");
5717         } else {
5718                 emitcode ("mov","ma,%s",aopGet(AOP(left),0,FALSE,FALSE,NULL));
5719                 emitcode ("mov","ma,%s",aopGet(AOP(left),1,FALSE,FALSE,NULL));
5720         }
5721
5722         /* load up MB with right */
5723         if (!umult) {
5724                 if (AOP_TYPE(right) == AOP_LIT) {
5725                         int val=(int)floatFromVal (AOP (right)->aopu.aop_lit);
5726                         if (val < 0) {
5727                                 val = -val;
5728                         }
5729                         emitcode ("mov","mb,#!constbyte",val & 0xff);
5730                         emitcode ("mov","mb,#!constbyte",(val >> 8) & 0xff);
5731                 } else {
5732                         lbl = newiTempLabel(NULL);
5733                         emitcode ("mov","b,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5734                         emitcode ("mov","a,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5735                         emitcode ("jnb","acc.7,!tlabel",lbl->key+100);
5736                         emitcode ("xch", "a,b");
5737                         emitcode ("cpl","a");
5738                         emitcode ("add", "a,#1");
5739                         emitcode ("xch", "a,b");
5740                         emitcode ("cpl", "a"); // msb
5741                         emitcode ("addc", "a,#0");
5742                         emitcode ("","!tlabeldef",lbl->key+100);
5743                         emitcode ("mov","mb,b");
5744                         emitcode ("mov","mb,a");
5745                 }
5746         } else {
5747                 emitcode ("mov","mb,%s",aopGet(AOP(right),0,FALSE,FALSE,NULL));
5748                 emitcode ("mov","mb,%s",aopGet(AOP(right),1,FALSE,FALSE,NULL));
5749         }
5750
5751         /* wait for multiplication to finish */
5752         lbl = newiTempLabel(NULL);
5753         emitcode("","!tlabeldef", lbl->key+100);
5754         emitcode("mov","a,mcnt1");
5755         emitcode("anl","a,#!constbyte",0x80);
5756         emitcode("jnz","!tlabel",lbl->key+100);
5757
5758         freeAsmop (left, NULL, ic, TRUE);
5759         freeAsmop (right, NULL, ic,TRUE);
5760         aopOp(result, ic, TRUE, FALSE);
5761
5762         aopPut(AOP(result),"mb",1);
5763         aopPut(AOP(result),"mb",0);
5764         freeAsmop (result, NULL, ic, TRUE);
5765
5766         /* restore EA bit in F1 */
5767         lbl = newiTempLabel(NULL);
5768         emitcode ("jnb","F1,!tlabel",lbl->key+100);
5769         emitcode ("setb","EA");
5770         emitcode("","!tlabeldef",lbl->key+100);
5771         return ;
5772 }
5773
5774 /*-----------------------------------------------------------------*/
5775 /* genMod - generates code for division                            */
5776 /*-----------------------------------------------------------------*/
5777 static void
5778 genMod (iCode * ic)
5779 {
5780   operand *left = IC_LEFT (ic);
5781   operand *right = IC_RIGHT (ic);
5782   operand *result = IC_RESULT (ic);
5783
5784   D (emitcode (";", "genMod "); );
5785
5786   /* assign the amsops */
5787   AOP_OP_2 (ic);
5788
5789   /* special cases first */
5790   /* both are bits */
5791   if (AOP_TYPE (left) == AOP_CRY &&
5792       AOP_TYPE (right) == AOP_CRY)
5793     {
5794       genModbits (left, right, result, ic);
5795       goto release;
5796     }
5797
5798   /* if both are of size == 1 */
5799   if (AOP_SIZE (left) == 1 &&
5800       AOP_SIZE (right) == 1)
5801     {
5802       genModOneByte (left, right, result, ic);
5803       goto release;
5804     }
5805
5806   if (AOP_SIZE (left) == 2 && AOP_SIZE(right) == 2) {
5807           /* use the ds390 ARITHMETIC accel UNIT */
5808           genModTwoByte (left, right, result, ic);
5809           return ;
5810   }
5811
5812   /* should have been converted to function call */
5813   assert (0);
5814
5815 release:
5816   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5817   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5818   freeAsmop (result, NULL, ic, TRUE);
5819 }
5820
5821 /*-----------------------------------------------------------------*/
5822 /* genIfxJump :- will create a jump depending on the ifx           */
5823 /*-----------------------------------------------------------------*/
5824 static void
5825 genIfxJump (iCode * ic, char *jval)
5826 {
5827   symbol *jlbl;
5828   symbol *tlbl = newiTempLabel (NULL);
5829   char *inst;
5830
5831   D (emitcode (";", "genIfxJump"););
5832
5833   /* if true label then we jump if condition
5834      supplied is true */
5835   if (IC_TRUE (ic))
5836     {
5837       jlbl = IC_TRUE (ic);
5838       inst = ((strcmp (jval, "a") == 0 ? "jz" :
5839                (strcmp (jval, "c") == 0 ? "jnc" : "jnb")));
5840     }
5841   else
5842     {
5843       /* false label is present */
5844       jlbl = IC_FALSE (ic);
5845       inst = ((strcmp (jval, "a") == 0 ? "jnz" :
5846                (strcmp (jval, "c") == 0 ? "jc" : "jb")));
5847     }
5848   if (strcmp (inst, "jb") == 0 || strcmp (inst, "jnb") == 0)
5849     emitcode (inst, "%s,!tlabel", jval, (tlbl->key + 100));
5850   else
5851     emitcode (inst, "!tlabel", tlbl->key + 100);
5852   emitcode ("ljmp", "!tlabel", jlbl->key + 100);
5853   emitcode ("", "!tlabeldef", tlbl->key + 100);
5854
5855   /* mark the icode as generated */
5856   ic->generated = 1;
5857 }
5858
5859 /*-----------------------------------------------------------------*/
5860 /* genCmp :- greater or less than comparison                       */
5861 /*-----------------------------------------------------------------*/
5862 static void
5863 genCmp (operand * left, operand * right,
5864         iCode * ic, iCode * ifx, int sign)
5865 {
5866   int size, offset = 0;
5867   unsigned long lit = 0L;
5868   operand *result;
5869
5870   D (emitcode (";", "genCmp"););
5871
5872   result = IC_RESULT (ic);
5873
5874   /* if left & right are bit variables */
5875   if (AOP_TYPE (left) == AOP_CRY &&
5876       AOP_TYPE (right) == AOP_CRY)
5877     {
5878       emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
5879       emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
5880     }
5881   else
5882     {
5883       /* subtract right from left if at the
5884          end the carry flag is set then we know that
5885          left is greater than right */
5886       size = max (AOP_SIZE (left), AOP_SIZE (right));
5887
5888       /* if unsigned char cmp with lit, do cjne left,#right,zz */
5889       if ((size == 1) && !sign
5890           && (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR && AOP_TYPE (left) != AOP_STR))
5891         {
5892           symbol *lbl = newiTempLabel (NULL);
5893           emitcode ("cjne", "%s,%s,!tlabel",
5894                     aopGet (AOP (left), offset, FALSE, FALSE, NULL),
5895                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
5896                     lbl->key + 100);
5897           emitcode ("", "!tlabeldef", lbl->key + 100);
5898         }
5899       else
5900         {
5901           if (AOP_TYPE (right) == AOP_LIT)
5902             {
5903               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
5904               /* optimize if(x < 0) or if(x >= 0) */
5905               if (lit == 0L)
5906                 {
5907                   if (!sign)
5908                     {
5909                       CLRC;
5910                     }
5911                   else
5912                     {
5913                       MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
5914
5915                       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5916                       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5917
5918                       aopOp (result, ic, FALSE, FALSE);
5919
5920                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
5921                         {
5922                           freeAsmop (result, NULL, ic, TRUE);
5923                           genIfxJump (ifx, "acc.7");
5924                           return;
5925                         }
5926                       else
5927                         {
5928                           emitcode ("rlc", "a");
5929                         }
5930                       goto release_freedLR;
5931                     }
5932                   goto release;
5933                 }
5934             }
5935           CLRC;
5936           while (size--)
5937             {
5938               // emitcode (";", "genCmp #1: %d/%d/%d", size, sign, offset);
5939               MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
5940               // emitcode (";", "genCmp #2");
5941               if (sign && (size == 0))
5942                 {
5943                   // emitcode (";", "genCmp #3");
5944                   emitcode ("xrl", "a,#!constbyte",0x80);
5945                   if (AOP_TYPE (right) == AOP_LIT)
5946                     {
5947                       unsigned long lit = (unsigned long)
5948                       floatFromVal (AOP (right)->aopu.aop_lit);
5949                       // emitcode (";", "genCmp #3.1");
5950                       emitcode ("subb", "a,#!constbyte",
5951                                 0x80 ^ (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
5952                     }
5953                   else
5954                     {
5955                       // emitcode (";", "genCmp #3.2");
5956                       saveAccWarn = 0;
5957                       MOVB(aopGet (AOP (right), offset++, FALSE, FALSE, "b"));
5958                       saveAccWarn = DEFAULT_ACC_WARNING;
5959                       emitcode ("xrl", "b,#!constbyte",0x80);
5960                       emitcode ("subb", "a,b");
5961                     }
5962                 }
5963               else
5964                 {
5965                   const char *s;
5966
5967                   // emitcode (";", "genCmp #4");
5968                   saveAccWarn = 0;
5969                   s = aopGet (AOP (right), offset++, FALSE, FALSE, "b");
5970                   saveAccWarn = DEFAULT_ACC_WARNING;
5971
5972                   emitcode ("subb", "a,%s", s);
5973                 }
5974             }
5975         }
5976     }
5977
5978 release:
5979 /* Don't need the left & right operands any more; do need the result. */
5980   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5981   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
5982
5983   aopOp (result, ic, FALSE, FALSE);
5984
5985 release_freedLR:
5986
5987   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
5988     {
5989       outBitC (result);
5990     }
5991   else
5992     {
5993       /* if the result is used in the next
5994          ifx conditional branch then generate
5995          code a little differently */
5996       if (ifx)
5997         {
5998           genIfxJump (ifx, "c");
5999         }
6000       else
6001         {
6002           outBitC (result);
6003         }
6004       /* leave the result in acc */
6005     }
6006   freeAsmop (result, NULL, ic, TRUE);
6007 }
6008
6009 /*-----------------------------------------------------------------*/
6010 /* genCmpGt :- greater than comparison                             */
6011 /*-----------------------------------------------------------------*/
6012 static void
6013 genCmpGt (iCode * ic, iCode * ifx)
6014 {
6015   operand *left, *right;
6016   sym_link *letype, *retype;
6017   int sign;
6018
6019   D (emitcode (";", "genCmpGt ");
6020     );
6021
6022   left = IC_LEFT (ic);
6023   right = IC_RIGHT (ic);
6024
6025   letype = getSpec (operandType (left));
6026   retype = getSpec (operandType (right));
6027   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6028
6029   /* assign the left & right amsops */
6030   AOP_OP_2 (ic);
6031
6032   genCmp (right, left, ic, ifx, sign);
6033 }
6034
6035 /*-----------------------------------------------------------------*/
6036 /* genCmpLt - less than comparisons                                */
6037 /*-----------------------------------------------------------------*/
6038 static void
6039 genCmpLt (iCode * ic, iCode * ifx)
6040 {
6041   operand *left, *right;
6042   sym_link *letype, *retype;
6043   int sign;
6044
6045   D (emitcode (";", "genCmpLt "););
6046
6047   left = IC_LEFT (ic);
6048   right = IC_RIGHT (ic);
6049
6050   letype = getSpec (operandType (left));
6051   retype = getSpec (operandType (right));
6052   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
6053
6054   /* assign the left & right amsops */
6055   AOP_OP_2 (ic);
6056
6057   genCmp (left, right, ic, ifx, sign);
6058 }
6059
6060 /*-----------------------------------------------------------------*/
6061 /* gencjneshort - compare and jump if not equal                    */
6062 /*-----------------------------------------------------------------*/
6063 static void
6064 gencjneshort (operand * left, operand * right, symbol * lbl)
6065 {
6066   int size = max (AOP_SIZE (left), AOP_SIZE (right));
6067   int offset = 0;
6068   unsigned long lit = 0L;
6069
6070   D (emitcode (";", "gencjneshort");
6071     );
6072
6073   /* if the left side is a literal or
6074      if the right is in a pointer register and left
6075      is not */
6076   if ((AOP_TYPE (left) == AOP_LIT) ||
6077       (AOP_TYPE (left) == AOP_IMMD) ||
6078       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6079     {
6080       operand *t = right;
6081       right = left;
6082       left = t;
6083     }
6084
6085   if (AOP_TYPE (right) == AOP_LIT)
6086     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6087
6088   if (opIsGptr (left) || opIsGptr (right))
6089     {
6090       /* We are comparing a generic pointer to something.
6091        * Exclude the generic type byte from the comparison.
6092        */
6093       size--;
6094       D (emitcode (";", "cjneshort: generic ptr special case."););
6095     }
6096
6097
6098   /* if the right side is a literal then anything goes */
6099   if (AOP_TYPE (right) == AOP_LIT &&
6100       AOP_TYPE (left) != AOP_DIR)
6101     {
6102       while (size--)
6103         {
6104           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6105           emitcode ("cjne", "a,%s,!tlabel",
6106                     aopGet (AOP (right), offset, FALSE, FALSE, NULL),
6107                     lbl->key + 100);
6108           offset++;
6109         }
6110     }
6111
6112   /* if the right side is in a register or in direct space or
6113      if the left is a pointer register & right is not */
6114   else if (AOP_TYPE (right) == AOP_REG ||
6115            AOP_TYPE (right) == AOP_DIR ||
6116            AOP_TYPE (right) == AOP_LIT ||
6117            AOP_TYPE (right) == AOP_IMMD ||
6118            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) ||
6119            (IS_AOP_PREG (left) && !IS_AOP_PREG (right)))
6120     {
6121       while (size--)
6122         {
6123           MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6124           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
6125               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
6126             emitcode ("jnz", "!tlabel", lbl->key + 100);
6127           else
6128             emitcode ("cjne", "a,%s,!tlabel",
6129                       aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG),
6130                       lbl->key + 100);
6131           offset++;
6132         }
6133     }
6134   else
6135     {
6136       /* right is a pointer reg need both a & b */
6137       while (size--)
6138         {
6139           MOVB (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6140           MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6141           emitcode ("cjne", "a,b,!tlabel", lbl->key + 100);
6142           offset++;
6143         }
6144     }
6145 }
6146
6147 /*-----------------------------------------------------------------*/
6148 /* gencjne - compare and jump if not equal                         */
6149 /*-----------------------------------------------------------------*/
6150 static void
6151 gencjne (operand * left, operand * right, symbol * lbl)
6152 {
6153   symbol *tlbl = newiTempLabel (NULL);
6154
6155   D (emitcode (";", "gencjne");
6156     );
6157
6158   gencjneshort (left, right, lbl);
6159
6160   emitcode ("mov", "a,%s", one);
6161   emitcode ("sjmp", "!tlabel", tlbl->key + 100);
6162   emitcode ("", "!tlabeldef", lbl->key + 100);
6163   emitcode ("clr", "a");
6164   emitcode ("", "!tlabeldef", tlbl->key + 100);
6165 }
6166
6167 /*-----------------------------------------------------------------*/
6168 /* genCmpEq - generates code for equal to                          */
6169 /*-----------------------------------------------------------------*/
6170 static void
6171 genCmpEq (iCode * ic, iCode * ifx)
6172 {
6173   operand *left, *right, *result;
6174
6175   D (emitcode (";", "genCmpEq ");
6176     );
6177
6178   AOP_OP_2 (ic);
6179   AOP_SET_LOCALS (ic);
6180
6181   /* if literal, literal on the right or
6182      if the right is in a pointer register and left
6183      is not */
6184   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
6185       (IS_AOP_PREG (right) && !IS_AOP_PREG (left)))
6186     {
6187       operand *t = IC_RIGHT (ic);
6188       IC_RIGHT (ic) = IC_LEFT (ic);
6189       IC_LEFT (ic) = t;
6190     }
6191
6192   if (ifx &&                    /* !AOP_SIZE(result) */
6193       OP_SYMBOL (result) &&
6194       OP_SYMBOL (result)->regType == REG_CND)
6195     {
6196       symbol *tlbl;
6197       /* if they are both bit variables */
6198       if (AOP_TYPE (left) == AOP_CRY &&
6199           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6200         {
6201           if (AOP_TYPE (right) == AOP_LIT)
6202             {
6203               unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6204               if (lit == 0L)
6205                 {
6206                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6207                   emitcode ("cpl", "c");
6208                 }
6209               else if (lit == 1L)
6210                 {
6211                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6212                 }
6213               else
6214                 {
6215                   emitcode ("clr", "c");
6216                 }
6217               /* AOP_TYPE(right) == AOP_CRY */
6218             }
6219           else
6220             {
6221               symbol *lbl = newiTempLabel (NULL);
6222               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6223               emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6224               emitcode ("cpl", "c");
6225               emitcode ("", "!tlabeldef", (lbl->key + 100));
6226             }
6227           /* if true label then we jump if condition
6228              supplied is true */
6229           tlbl = newiTempLabel (NULL);
6230           if (IC_TRUE (ifx))
6231             {
6232               emitcode ("jnc", "!tlabel", tlbl->key + 100);
6233               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6234             }
6235           else
6236             {
6237               emitcode ("jc", "!tlabel", tlbl->key + 100);
6238               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6239             }
6240           emitcode ("", "!tlabeldef", tlbl->key + 100);
6241         }
6242       else
6243         {
6244           tlbl = newiTempLabel (NULL);
6245           gencjneshort (left, right, tlbl);
6246           if (IC_TRUE (ifx))
6247             {
6248               emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
6249               emitcode ("", "!tlabeldef", tlbl->key + 100);
6250             }
6251           else
6252             {
6253               symbol *lbl = newiTempLabel (NULL);
6254               emitcode ("sjmp", "!tlabel", lbl->key + 100);
6255               emitcode ("", "!tlabeldef", tlbl->key + 100);
6256               emitcode ("ljmp", "!tlabel", IC_FALSE (ifx)->key + 100);
6257               emitcode ("", "!tlabeldef", lbl->key + 100);
6258             }
6259         }
6260       /* mark the icode as generated */
6261       ifx->generated = 1;
6262
6263       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6264       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6265       return;
6266     }
6267
6268   /* if they are both bit variables */
6269   if (AOP_TYPE (left) == AOP_CRY &&
6270       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
6271     {
6272       if (AOP_TYPE (right) == AOP_LIT)
6273         {
6274           unsigned long lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6275           if (lit == 0L)
6276             {
6277               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6278               emitcode ("cpl", "c");
6279             }
6280           else if (lit == 1L)
6281             {
6282               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6283             }
6284           else
6285             {
6286               emitcode ("clr", "c");
6287             }
6288           /* AOP_TYPE(right) == AOP_CRY */
6289         }
6290       else
6291         {
6292           symbol *lbl = newiTempLabel (NULL);
6293           emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6294           emitcode ("jb", "%s,!tlabel", AOP (right)->aopu.aop_dir, (lbl->key + 100));
6295           emitcode ("cpl", "c");
6296           emitcode ("", "!tlabeldef", (lbl->key + 100));
6297         }
6298
6299       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6300       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6301
6302       aopOp (result, ic, TRUE, FALSE);
6303
6304       /* c = 1 if egal */
6305       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6306         {
6307           outBitC (result);
6308           goto release;
6309         }
6310       if (ifx)
6311         {
6312           genIfxJump (ifx, "c");
6313           goto release;
6314         }
6315       /* if the result is used in an arithmetic operation
6316          then put the result in place */
6317       outBitC (result);
6318     }
6319   else
6320     {
6321       gencjne (left, right, newiTempLabel (NULL));
6322
6323       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6324       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6325
6326       aopOp (result, ic, TRUE, FALSE);
6327
6328       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
6329         {
6330           aopPut (AOP (result), "a", 0);
6331           goto release;
6332         }
6333       if (ifx)
6334         {
6335           genIfxJump (ifx, "a");
6336           goto release;
6337         }
6338       /* if the result is used in an arithmetic operation
6339          then put the result in place */
6340       if (AOP_TYPE (result) != AOP_CRY)
6341         outAcc (result);
6342       /* leave the result in acc */
6343     }
6344
6345 release:
6346   freeAsmop (result, NULL, ic, TRUE);
6347 }
6348
6349 /*-----------------------------------------------------------------*/
6350 /* ifxForOp - returns the icode containing the ifx for operand     */
6351 /*-----------------------------------------------------------------*/
6352 static iCode *
6353 ifxForOp (operand * op, iCode * ic)
6354 {
6355   /* if true symbol then needs to be assigned */
6356   if (IS_TRUE_SYMOP (op))
6357     return NULL;
6358
6359   /* if this has register type condition and
6360      the next instruction is ifx with the same operand
6361      and live to of the operand is upto the ifx only then */
6362   if (ic->next &&
6363       ic->next->op == IFX &&
6364       IC_COND (ic->next)->key == op->key &&
6365       OP_SYMBOL (op)->liveTo <= ic->next->seq)
6366     return ic->next;
6367
6368   return NULL;
6369 }
6370 /*-----------------------------------------------------------------*/
6371 /* hasInc - operand is incremented before any other use            */
6372 /*-----------------------------------------------------------------*/
6373 static iCode *
6374 hasInc (operand *op, iCode *ic, int osize)
6375 {
6376   sym_link *type = operandType(op);
6377   sym_link *retype = getSpec (type);
6378   iCode *lic = ic->next;
6379   int isize ;
6380
6381   /* this could from a cast, e.g.: "(char xdata *) 0x7654;" */
6382   if (!IS_SYMOP(op)) return NULL;
6383
6384   if (IS_BITVAR(retype)||!IS_PTR(type)) return NULL;
6385   if (IS_AGGREGATE(type->next)) return NULL;
6386   if (osize != (isize = getSize(type->next))) return NULL;
6387
6388   while (lic) {
6389       /* if operand of the form op = op + <sizeof *op> */
6390       if (lic->op == '+' && isOperandEqual(IC_LEFT(lic),op) &&
6391           isOperandEqual(IC_RESULT(lic),op) &&
6392           isOperandLiteral(IC_RIGHT(lic)) &&
6393           operandLitValue(IC_RIGHT(lic)) == isize) {
6394           return lic;
6395       }
6396       /* if the operand used or deffed */
6397       if (bitVectBitValue(OP_USES(op),lic->key) || (unsigned) lic->defKey == op->key) {
6398           return NULL;
6399       }
6400       /* if GOTO or IFX */
6401       if (lic->op == IFX || lic->op == GOTO || lic->op == LABEL) break;
6402       lic = lic->next;
6403   }
6404   return NULL;
6405 }
6406
6407 /*-----------------------------------------------------------------*/
6408 /* genAndOp - for && operation                                     */
6409 /*-----------------------------------------------------------------*/
6410 static void
6411 genAndOp (iCode * ic)
6412 {
6413   operand *left, *right, *result;
6414   symbol *tlbl;
6415
6416   D (emitcode (";", "genAndOp "););
6417
6418   /* note here that && operations that are in an
6419      if statement are taken away by backPatchLabels
6420      only those used in arthmetic operations remain */
6421   AOP_OP_2 (ic);
6422   AOP_SET_LOCALS (ic);
6423
6424   /* if both are bit variables */
6425   if (AOP_TYPE (left) == AOP_CRY &&
6426       AOP_TYPE (right) == AOP_CRY)
6427     {
6428       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6429       emitcode ("anl", "c,%s", AOP (right)->aopu.aop_dir);
6430       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6431       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6432
6433       aopOp (result,ic,FALSE, FALSE);
6434       outBitC (result);
6435     }
6436   else
6437     {
6438       tlbl = newiTempLabel (NULL);
6439       toBoolean (left);
6440       emitcode ("jz", "!tlabel", tlbl->key + 100);
6441       toBoolean (right);
6442       emitcode ("", "!tlabeldef", tlbl->key + 100);
6443       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6444       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6445
6446       aopOp (result,ic,FALSE, FALSE);
6447       outBitAcc (result);
6448     }
6449     freeAsmop (result, NULL, ic, TRUE);
6450 }
6451
6452
6453 /*-----------------------------------------------------------------*/
6454 /* genOrOp - for || operation                                      */
6455 /*-----------------------------------------------------------------*/
6456 static void
6457 genOrOp (iCode * ic)
6458 {
6459   operand *left, *right, *result;
6460   symbol *tlbl;
6461
6462   D (emitcode (";", "genOrOp "););
6463
6464   /* note here that || operations that are in an
6465      if statement are taken away by backPatchLabels
6466      only those used in arthmetic operations remain */
6467   AOP_OP_2 (ic);
6468   AOP_SET_LOCALS (ic);
6469
6470   /* if both are bit variables */
6471   if (AOP_TYPE (left) == AOP_CRY &&
6472       AOP_TYPE (right) == AOP_CRY)
6473     {
6474       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6475       emitcode ("orl", "c,%s", AOP (right)->aopu.aop_dir);
6476       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6477       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6478
6479       aopOp (result,ic,FALSE, FALSE);
6480
6481       outBitC (result);
6482     }
6483   else
6484     {
6485       tlbl = newiTempLabel (NULL);
6486       toBoolean (left);
6487       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6488       toBoolean (right);
6489       emitcode ("", "!tlabeldef", tlbl->key + 100);
6490       freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6491       freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6492
6493       aopOp (result,ic,FALSE, FALSE);
6494
6495       outBitAcc (result);
6496     }
6497
6498   freeAsmop (result, NULL, ic, TRUE);
6499 }
6500
6501 /*-----------------------------------------------------------------*/
6502 /* isLiteralBit - test if lit == 2^n                               */
6503 /*-----------------------------------------------------------------*/
6504 static int
6505 isLiteralBit (unsigned long lit)
6506 {
6507   unsigned long pw[32] =
6508   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
6509    0x100L, 0x200L, 0x400L, 0x800L,
6510    0x1000L, 0x2000L, 0x4000L, 0x8000L,
6511    0x10000L, 0x20000L, 0x40000L, 0x80000L,
6512    0x100000L, 0x200000L, 0x400000L, 0x800000L,
6513    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
6514    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
6515   int idx;
6516
6517   for (idx = 0; idx < 32; idx++)
6518     if (lit == pw[idx])
6519       return idx + 1;
6520   return 0;
6521 }
6522
6523 /*-----------------------------------------------------------------*/
6524 /* continueIfTrue -                                                */
6525 /*-----------------------------------------------------------------*/
6526 static void
6527 continueIfTrue (iCode * ic)
6528 {
6529   if (IC_TRUE (ic))
6530     emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6531   ic->generated = 1;
6532 }
6533
6534 /*-----------------------------------------------------------------*/
6535 /* jmpIfTrue -                                                     */
6536 /*-----------------------------------------------------------------*/
6537 static void
6538 jumpIfTrue (iCode * ic)
6539 {
6540   if (!IC_TRUE (ic))
6541     emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6542   ic->generated = 1;
6543 }
6544
6545 /*-----------------------------------------------------------------*/
6546 /* jmpTrueOrFalse -                                                */
6547 /*-----------------------------------------------------------------*/
6548 static void
6549 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
6550 {
6551   // ugly but optimized by peephole
6552   if (IC_TRUE (ic))
6553     {
6554       symbol *nlbl = newiTempLabel (NULL);
6555       emitcode ("sjmp", "!tlabel", nlbl->key + 100);
6556       emitcode ("", "!tlabeldef", tlbl->key + 100);
6557       emitcode ("ljmp", "!tlabel", IC_TRUE (ic)->key + 100);
6558       emitcode ("", "!tlabeldef", nlbl->key + 100);
6559     }
6560   else
6561     {
6562       emitcode ("ljmp", "!tlabel", IC_FALSE (ic)->key + 100);
6563       emitcode ("", "!tlabeldef", tlbl->key + 100);
6564     }
6565   ic->generated = 1;
6566 }
6567
6568 // Generate code to perform a bit-wise logic operation
6569 // on two operands in far space (assumed to already have been
6570 // aopOp'd by the AOP_OP_3_NOFATAL macro), storing the result
6571 // in far space. This requires pushing the result on the stack
6572 // then popping it into the result.
6573 static void
6574 genFarFarLogicOp(iCode *ic, char *logicOp)
6575 {
6576       int size, resultSize, compSize;
6577       int offset = 0;
6578
6579       TR_AP("#5");
6580       D(emitcode(";", "%s special case for 3 far operands.", logicOp););
6581       compSize = AOP_SIZE(IC_LEFT(ic)) < AOP_SIZE(IC_RIGHT(ic)) ?
6582                   AOP_SIZE(IC_LEFT(ic)) : AOP_SIZE(IC_RIGHT(ic));
6583
6584       _startLazyDPSEvaluation();
6585       for (size = compSize; (size--); offset++)
6586       {
6587           MOVA (aopGet (AOP (IC_LEFT(ic)), offset, FALSE, FALSE, NULL));
6588           emitcode ("mov", "%s, acc", DP2_RESULT_REG);
6589           MOVA (aopGet (AOP (IC_RIGHT(ic)), offset, FALSE, FALSE, NULL));
6590
6591           emitcode (logicOp, "a,%s", DP2_RESULT_REG);
6592           emitcode ("push", "acc");
6593       }
6594       _endLazyDPSEvaluation();
6595
6596       freeAsmop (IC_LEFT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6597       freeAsmop (IC_RIGHT(ic), NULL, ic, RESULTONSTACK (ic) ? FALSE : TRUE);
6598       aopOp (IC_RESULT(ic),ic,TRUE, FALSE);
6599
6600       resultSize = AOP_SIZE(IC_RESULT(ic));
6601
6602       ADJUST_PUSHED_RESULT(compSize, resultSize);
6603
6604       _startLazyDPSEvaluation();
6605       while (compSize--)
6606       {
6607           emitcode ("pop", "acc");
6608           aopPut (AOP (IC_RESULT (ic)), "a", compSize);
6609       }
6610       _endLazyDPSEvaluation();
6611       freeAsmop(IC_RESULT (ic), NULL, ic, TRUE);
6612 }
6613
6614
6615 /*-----------------------------------------------------------------*/
6616 /* genAnd  - code for and                                          */
6617 /*-----------------------------------------------------------------*/
6618 static void
6619 genAnd (iCode * ic, iCode * ifx)
6620 {
6621   operand *left, *right, *result;
6622   int size, offset = 0;
6623   unsigned long lit = 0L;
6624   int bytelit;
6625   char buff[10];
6626   bool pushResult;
6627
6628   D (emitcode (";", "genAnd "););
6629
6630   AOP_OP_3_NOFATAL (ic, pushResult);
6631   AOP_SET_LOCALS (ic);
6632
6633   if (pushResult)
6634   {
6635       genFarFarLogicOp(ic, "anl");
6636       return;
6637   }
6638
6639 #ifdef DEBUG_TYPE
6640   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6641             AOP_TYPE (result),
6642             AOP_TYPE (left), AOP_TYPE (right));
6643   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
6644             AOP_SIZE (result),
6645             AOP_SIZE (left), AOP_SIZE (right));
6646 #endif
6647
6648   /* if left is a literal & right is not then exchange them */
6649   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
6650 #ifdef LOGIC_OPS_BROKEN
6651     ||  AOP_NEEDSACC (left)
6652 #endif
6653     )
6654     {
6655       operand *tmp = right;
6656       right = left;
6657       left = tmp;
6658     }
6659
6660   /* if result = right then exchange left and right */
6661   if (sameRegs (AOP (result), AOP (right)))
6662     {
6663       operand *tmp = right;
6664       right = left;
6665       left = tmp;
6666     }
6667
6668   /* if right is bit then exchange them */
6669   if (AOP_TYPE (right) == AOP_CRY &&
6670       AOP_TYPE (left) != AOP_CRY)
6671     {
6672       operand *tmp = right;
6673       right = left;
6674       left = tmp;
6675     }
6676   if (AOP_TYPE (right) == AOP_LIT)
6677     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6678
6679   size = AOP_SIZE (result);
6680
6681   // if(bit & yy)
6682   // result = bit & yy;
6683   if (AOP_TYPE (left) == AOP_CRY)
6684     {
6685       // c = bit & literal;
6686       if (AOP_TYPE (right) == AOP_LIT)
6687         {
6688           if (lit & 1)
6689             {
6690               if (size && sameRegs (AOP (result), AOP (left)))
6691                 // no change
6692                 goto release;
6693               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
6694             }
6695           else
6696             {
6697               // bit(result) = 0;
6698               if (size && (AOP_TYPE (result) == AOP_CRY))
6699                 {
6700                   emitcode ("clr", "%s", AOP (result)->aopu.aop_dir);
6701                   goto release;
6702                 }
6703               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6704                 {
6705                   jumpIfTrue (ifx);
6706                   goto release;
6707                 }
6708               emitcode ("clr", "c");
6709             }
6710         }
6711       else
6712         {
6713           if (AOP_TYPE (right) == AOP_CRY)
6714             {
6715               // c = bit & bit;
6716               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
6717               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6718             }
6719           else
6720             {
6721               // c = bit & val;
6722               MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
6723               // c = lsb
6724               emitcode ("rrc", "a");
6725               emitcode ("anl", "c,%s", AOP (left)->aopu.aop_dir);
6726             }
6727         }
6728       // bit = c
6729       // val = c
6730       if (size)
6731         outBitC (result);
6732       // if(bit & ...)
6733       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
6734         genIfxJump (ifx, "c");
6735       goto release;
6736     }
6737
6738   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
6739   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
6740   if ((AOP_TYPE (right) == AOP_LIT) &&
6741       (AOP_TYPE (result) == AOP_CRY) &&
6742       (AOP_TYPE (left) != AOP_CRY))
6743     {
6744       int posbit = isLiteralBit (lit);
6745       /* left &  2^n */
6746       if (posbit)
6747         {
6748           posbit--;
6749           MOVA (aopGet (AOP (left), posbit >> 3, FALSE, FALSE, NULL));
6750           // bit = left & 2^n
6751           if (size)
6752             emitcode ("mov", "c,acc.%d", posbit & 0x07);
6753           // if(left &  2^n)
6754           else
6755             {
6756               if (ifx)
6757                 {
6758                   SNPRINTF (buff, sizeof(buff),
6759                             "acc.%d", posbit & 0x07);
6760                   genIfxJump (ifx, buff);
6761                 }
6762               else
6763                   {
6764                       emitcode ("anl","a,#!constbyte",1 << (posbit & 0x07));
6765                   }
6766               goto release;
6767             }
6768         }
6769       else
6770         {
6771           symbol *tlbl = newiTempLabel (NULL);
6772           int sizel = AOP_SIZE (left);
6773           if (size)
6774             emitcode ("setb", "c");
6775           while (sizel--)
6776             {
6777               if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
6778                 {
6779                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6780                   // byte ==  2^n ?
6781                   if ((posbit = isLiteralBit (bytelit)) != 0)
6782                     emitcode ("jb", "acc.%d,!tlabel", (posbit - 1) & 0x07, tlbl->key + 100);
6783                   else
6784                     {
6785                       if (bytelit != 0x0FFL)
6786                         emitcode ("anl", "a,%s",
6787                           aopGet (AOP (right), offset, FALSE, TRUE, DP2_RESULT_REG));
6788                       emitcode ("jnz", "!tlabel", tlbl->key + 100);
6789                     }
6790                 }
6791               offset++;
6792             }
6793           // bit = left & literal
6794           if (size)
6795             {
6796               emitcode ("clr", "c");
6797               emitcode ("", "!tlabeldef", tlbl->key + 100);
6798             }
6799           // if(left & literal)
6800           else
6801             {
6802               if (ifx)
6803                 jmpTrueOrFalse (ifx, tlbl);
6804               else
6805                 emitcode ("", "!tlabeldef", tlbl->key + 100);
6806               goto release;
6807             }
6808         }
6809       outBitC (result);
6810       goto release;
6811     }
6812
6813   /* if left is same as result */
6814   if (sameRegs (AOP (result), AOP (left)))
6815     {
6816       for (; size--; offset++)
6817         {
6818           if (AOP_TYPE (right) == AOP_LIT)
6819             {
6820               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6821               if (bytelit == 0x0FF)
6822                 {
6823                   /* dummy read of volatile operand */
6824                   if (isOperandVolatile (left, FALSE))
6825                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6826                   else
6827                     continue;
6828                 }
6829               else if (bytelit == 0)
6830                 {
6831                   aopPut (AOP (result), zero, offset);
6832                 }
6833               else if (IS_AOP_PREG (result))
6834                 {
6835                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6836                   emitcode ("anl", "a,%s",
6837                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6838                   aopPut (AOP (result), "a", offset);
6839                 }
6840               else
6841                 emitcode ("anl", "%s,%s",
6842                           aopGet (AOP (left), offset, FALSE, TRUE, NULL),
6843                           aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6844             }
6845           else
6846             {
6847               if (AOP_TYPE (left) == AOP_ACC)
6848                 emitcode ("anl", "a,%s",
6849                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6850               else
6851                 {
6852                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6853                   if (IS_AOP_PREG (result))
6854                     {
6855                       emitcode ("anl", "a,%s",
6856                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6857                       aopPut (AOP (result), "a", offset);
6858                     }
6859                   else
6860                     emitcode ("anl", "%s,a",
6861                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
6862                 }
6863             }
6864         }
6865     }
6866   else
6867     {
6868       // left & result in different registers
6869       if (AOP_TYPE (result) == AOP_CRY)
6870         {
6871           // result = bit
6872           // if(size), result in bit
6873           // if(!size && ifx), conditional oper: if(left & right)
6874           symbol *tlbl = newiTempLabel (NULL);
6875           int sizer = min (AOP_SIZE (left), AOP_SIZE (right));
6876           if (size)
6877             emitcode ("setb", "c");
6878           while (sizer--)
6879             {
6880               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
6881                 emitcode ("anl", "a,%s",
6882                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6883               } else {
6884                 if (AOP_TYPE(left)==AOP_ACC) {
6885                   emitcode("mov", "b,a");
6886                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6887                   emitcode("anl", "a,b");
6888                 }else {
6889                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
6890                   emitcode ("anl", "a,%s",
6891                             aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
6892                 }
6893               }
6894               emitcode ("jnz", "!tlabel", tlbl->key + 100);
6895               offset++;
6896             }
6897           if (size)
6898             {
6899               CLRC;
6900               emitcode ("", "!tlabeldef", tlbl->key + 100);
6901               outBitC (result);
6902             }
6903           else if (ifx)
6904             jmpTrueOrFalse (ifx, tlbl);
6905           else
6906             emitcode ("", "!tlabeldef", tlbl->key + 100);
6907         }
6908       else
6909         {
6910           for (; (size--); offset++)
6911             {
6912               // normal case
6913               // result = left & right
6914               if (AOP_TYPE (right) == AOP_LIT)
6915                 {
6916                   bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
6917                   if (bytelit == 0x0FF)
6918                     {
6919                       aopPut (AOP (result),
6920                               aopGet (AOP (left), offset, FALSE, FALSE, NULL),
6921                               offset);
6922                       continue;
6923                     }
6924                   else if (bytelit == 0)
6925                     {
6926                       /* dummy read of volatile operand */
6927                       if (isOperandVolatile (left, FALSE))
6928                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6929                       aopPut (AOP (result), zero, offset);
6930                       continue;
6931                     }
6932                   D (emitcode (";", "better literal AND."););
6933                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6934                   emitcode ("anl", "a, %s", aopGet (AOP (right), offset,
6935                                                     FALSE, FALSE, DP2_RESULT_REG));
6936
6937                 }
6938               else
6939                 {
6940                   // faster than result <- left, anl result,right
6941                   // and better if result is SFR
6942                   if (AOP_TYPE (left) == AOP_ACC)
6943                     {
6944                       emitcode ("anl", "a,%s",
6945                                 aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
6946                     }
6947                   else
6948                     {
6949                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
6950                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
6951                       {
6952                           emitcode("mov", "b,a");
6953                           rOp = "b";
6954                       }
6955
6956                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
6957                       emitcode ("anl", "a,%s", rOp);
6958                     }
6959                 }
6960               aopPut (AOP (result), "a", offset);
6961             }
6962         }
6963     }
6964
6965 release:
6966   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6967   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
6968   freeAsmop (result, NULL, ic, TRUE);
6969 }
6970
6971
6972 /*-----------------------------------------------------------------*/
6973 /* genOr  - code for or                                            */
6974 /*-----------------------------------------------------------------*/
6975 static void
6976 genOr (iCode * ic, iCode * ifx)
6977 {
6978   operand *left, *right, *result;
6979   int size, offset = 0;
6980   unsigned long lit = 0L;
6981   int bytelit = 0;
6982   bool     pushResult;
6983
6984   D (emitcode (";", "genOr "););
6985
6986   AOP_OP_3_NOFATAL (ic, pushResult);
6987   AOP_SET_LOCALS (ic);
6988
6989   if (pushResult)
6990   {
6991       genFarFarLogicOp(ic, "orl");
6992       return;
6993   }
6994
6995
6996 #ifdef DEBUG_TYPE
6997   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
6998             AOP_TYPE (result),
6999             AOP_TYPE (left), AOP_TYPE (right));
7000   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7001             AOP_SIZE (result),
7002             AOP_SIZE (left), AOP_SIZE (right));
7003 #endif
7004
7005   /* if left is a literal & right is not then exchange them */
7006   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7007 #ifdef LOGIC_OPS_BROKEN
7008    || AOP_NEEDSACC (left) // I think this is a net loss now.
7009 #endif
7010       )
7011     {
7012       operand *tmp = right;
7013       right = left;
7014       left = tmp;
7015     }
7016
7017   /* if result = right then exchange them */
7018   if (sameRegs (AOP (result), AOP (right)))
7019     {
7020       operand *tmp = right;
7021       right = left;
7022       left = tmp;
7023     }
7024
7025   /* if right is bit then exchange them */
7026   if (AOP_TYPE (right) == AOP_CRY &&
7027       AOP_TYPE (left) != AOP_CRY)
7028     {
7029       operand *tmp = right;
7030       right = left;
7031       left = tmp;
7032     }
7033   if (AOP_TYPE (right) == AOP_LIT)
7034     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7035
7036   size = AOP_SIZE (result);
7037
7038   // if(bit | yy)
7039   // xx = bit | yy;
7040   if (AOP_TYPE (left) == AOP_CRY)
7041     {
7042       if (AOP_TYPE (right) == AOP_LIT)
7043         {
7044           // c = bit & literal;
7045           if (lit)
7046             {
7047               // lit != 0 => result = 1
7048               if (AOP_TYPE (result) == AOP_CRY)
7049                 {
7050                   if (size)
7051                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7052                   else if (ifx)
7053                     continueIfTrue (ifx);
7054                   goto release;
7055                 }
7056               emitcode ("setb", "c");
7057             }
7058           else
7059             {
7060               // lit == 0 => result = left
7061               if (size && sameRegs (AOP (result), AOP (left)))
7062                 goto release;
7063               emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7064             }
7065         }
7066       else
7067         {
7068           if (AOP_TYPE (right) == AOP_CRY)
7069             {
7070               // c = bit | bit;
7071               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7072               emitcode ("orl", "c,%s", AOP (left)->aopu.aop_dir);
7073             }
7074           else
7075             {
7076               // c = bit | val;
7077               symbol *tlbl = newiTempLabel (NULL);
7078               if (!((AOP_TYPE (result) == AOP_CRY) && ifx))
7079                 emitcode ("setb", "c");
7080               emitcode ("jb", "%s,!tlabel",
7081                         AOP (left)->aopu.aop_dir, tlbl->key + 100);
7082               toBoolean (right);
7083               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7084               if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7085                 {
7086                   jmpTrueOrFalse (ifx, tlbl);
7087                   goto release;
7088                 }
7089               else
7090                 {
7091                   CLRC;
7092                   emitcode ("", "!tlabeldef", tlbl->key + 100);
7093                 }
7094             }
7095         }
7096       // bit = c
7097       // val = c
7098       if (size)
7099         outBitC (result);
7100       // if(bit | ...)
7101       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7102            genIfxJump (ifx, "c");
7103       goto release;
7104     }
7105
7106   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
7107   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
7108   if ((AOP_TYPE (right) == AOP_LIT) &&
7109       (AOP_TYPE (result) == AOP_CRY) &&
7110       (AOP_TYPE (left) != AOP_CRY))
7111     {
7112       if (lit)
7113         {
7114           // result = 1
7115           if (size)
7116             emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7117           else
7118             continueIfTrue (ifx);
7119           goto release;
7120         }
7121       else
7122         {
7123           // lit = 0, result = boolean(left)
7124           if (size)
7125             emitcode ("setb", "c");
7126           toBoolean (right);
7127           if (size)
7128             {
7129               symbol *tlbl = newiTempLabel (NULL);
7130               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7131               CLRC;
7132               emitcode ("", "!tlabeldef", tlbl->key + 100);
7133             }
7134           else
7135             {
7136               genIfxJump (ifx, "a");
7137               goto release;
7138             }
7139         }
7140       outBitC (result);
7141       goto release;
7142     }
7143
7144   /* if left is same as result */
7145   if (sameRegs (AOP (result), AOP (left)))
7146     {
7147       for (; size--; offset++)
7148         {
7149           if (AOP_TYPE (right) == AOP_LIT)
7150             {
7151               bytelit = (int)((lit >> (offset * 8)) & 0x0FFL);
7152               if (bytelit == 0x00L)
7153                 {
7154                   /* dummy read of volatile operand */
7155                   if (isOperandVolatile (left, FALSE))
7156                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7157                   else
7158                     continue;
7159                 }
7160               else if (bytelit == 0x0FF)
7161                 {
7162                   aopPut (AOP (result), "#0xFF", offset);
7163                 }
7164               else if (IS_AOP_PREG (left))
7165                 {
7166                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7167                   emitcode ("orl", "a,%s",
7168                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7169                   aopPut (AOP (result), "a", offset);
7170                 }
7171               else
7172                 {
7173                   emitcode ("orl", "%s,%s",
7174                             aopGet (AOP (left), offset, FALSE, TRUE, NULL),
7175                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7176                 }
7177             }
7178           else
7179             {
7180               if (AOP_TYPE (left) == AOP_ACC)
7181                 {
7182                   emitcode ("orl", "a,%s",
7183                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7184                 }
7185               else
7186                 {
7187                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7188                   if (IS_AOP_PREG (left))
7189                     {
7190                       emitcode ("orl", "a,%s",
7191                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7192                       aopPut (AOP (result), "a", offset);
7193                     }
7194                   else
7195                     {
7196                       emitcode ("orl", "%s,a",
7197                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7198                     }
7199                 }
7200             }
7201         }
7202     }
7203   else
7204     {
7205       // left & result in different registers
7206       if (AOP_TYPE (result) == AOP_CRY)
7207         {
7208           // result = bit
7209           // if(size), result in bit
7210           // if(!size && ifx), conditional oper: if(left | right)
7211           symbol *tlbl = newiTempLabel (NULL);
7212           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7213           if (size)
7214             emitcode ("setb", "c");
7215           while (sizer--)
7216             {
7217               if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7218                 emitcode ("orl", "a,%s",
7219                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7220               } else {
7221                 MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7222                 emitcode ("orl", "a,%s",
7223                           aopGet (AOP (left), offset, FALSE, FALSE, DP2_RESULT_REG));
7224               }
7225               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7226               offset++;
7227             }
7228           if (size)
7229             {
7230               CLRC;
7231               emitcode ("", "!tlabeldef", tlbl->key + 100);
7232               outBitC (result);
7233             }
7234           else if (ifx)
7235             jmpTrueOrFalse (ifx, tlbl);
7236           else
7237             emitcode ("", "!tlabeldef", tlbl->key + 100);
7238         }
7239       else
7240         {
7241             _startLazyDPSEvaluation();
7242           for (; (size--); offset++)
7243             {
7244               // normal case
7245               // result = left & right
7246               if (AOP_TYPE (right) == AOP_LIT)
7247                 {
7248                   bytelit = (int)((lit >> (offset * 8)) & 0x0FFL);
7249                   if (bytelit == 0x00L)
7250                     {
7251                       aopPut (AOP (result),
7252                               aopGet (AOP (left), offset, FALSE, FALSE, NULL),
7253                               offset);
7254                       continue;
7255                     }
7256                   else if (bytelit == 0x0FF)
7257                     {
7258                       /* dummy read of volatile operand */
7259                       if (isOperandVolatile (left, FALSE))
7260                         MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7261                       aopPut (AOP (result), "#0xFF", offset);
7262                       continue;
7263                     }
7264                   D (emitcode (";", "better literal OR."););
7265                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7266                   emitcode ("orl", "a, %s",
7267                             aopGet (AOP (right), offset,
7268                                     FALSE, FALSE, DP2_RESULT_REG));
7269
7270                 }
7271               else
7272                 {
7273                   // faster than result <- left, anl result,right
7274                   // and better if result is SFR
7275                   if (AOP_TYPE (left) == AOP_ACC)
7276                     {
7277                       emitcode ("orl", "a,%s",
7278                                 aopGet (AOP (right), offset,
7279                                         FALSE, FALSE, DP2_RESULT_REG));
7280                     }
7281                   else
7282                     {
7283                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7284
7285                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7286                       {
7287                           emitcode("mov", "b,a");
7288                           rOp = "b";
7289                       }
7290
7291                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7292                       emitcode ("orl", "a,%s", rOp);
7293                     }
7294                 }
7295               aopPut (AOP (result), "a", offset);
7296             }
7297             _endLazyDPSEvaluation();
7298         }
7299     }
7300
7301 release:
7302   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7303   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7304   freeAsmop (result, NULL, ic, TRUE);
7305 }
7306
7307 /*-----------------------------------------------------------------*/
7308 /* genXor - code for xclusive or                                   */
7309 /*-----------------------------------------------------------------*/
7310 static void
7311 genXor (iCode * ic, iCode * ifx)
7312 {
7313   operand *left, *right, *result;
7314   int size, offset = 0;
7315   unsigned long lit = 0L;
7316   int bytelit = 0;
7317   bool pushResult;
7318
7319   D (emitcode (";", "genXor "););
7320
7321   AOP_OP_3_NOFATAL (ic, pushResult);
7322   AOP_SET_LOCALS (ic);
7323
7324   if (pushResult)
7325   {
7326       genFarFarLogicOp(ic, "xrl");
7327       return;
7328   }
7329
7330 #ifdef DEBUG_TYPE
7331   emitcode ("", "; Type res[%d] = l[%d]&r[%d]",
7332             AOP_TYPE (result),
7333             AOP_TYPE (left), AOP_TYPE (right));
7334   emitcode ("", "; Size res[%d] = l[%d]&r[%d]",
7335             AOP_SIZE (result),
7336             AOP_SIZE (left), AOP_SIZE (right));
7337 #endif
7338
7339   /* if left is a literal & right is not ||
7340      if left needs acc & right does not */
7341   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT)
7342 #ifdef LOGIC_OPS_BROKEN
7343       || (AOP_NEEDSACC (left) && !AOP_NEEDSACC (right))
7344 #endif
7345      )
7346     {
7347       operand *tmp = right;
7348       right = left;
7349       left = tmp;
7350     }
7351
7352   /* if result = right then exchange them */
7353   if (sameRegs (AOP (result), AOP (right)))
7354     {
7355       operand *tmp = right;
7356       right = left;
7357       left = tmp;
7358     }
7359
7360   /* if right is bit then exchange them */
7361   if (AOP_TYPE (right) == AOP_CRY &&
7362       AOP_TYPE (left) != AOP_CRY)
7363     {
7364       operand *tmp = right;
7365       right = left;
7366       left = tmp;
7367     }
7368   if (AOP_TYPE (right) == AOP_LIT)
7369     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
7370
7371   size = AOP_SIZE (result);
7372
7373   // if(bit ^ yy)
7374   // xx = bit ^ yy;
7375   if (AOP_TYPE (left) == AOP_CRY)
7376     {
7377       if (AOP_TYPE (right) == AOP_LIT)
7378         {
7379           // c = bit & literal;
7380           if (lit >> 1)
7381             {
7382               // lit>>1  != 0 => result = 1
7383               if (AOP_TYPE (result) == AOP_CRY)
7384                 {
7385                   if (size)
7386                     emitcode ("setb", "%s", AOP (result)->aopu.aop_dir);
7387                   else if (ifx)
7388                     continueIfTrue (ifx);
7389                   goto release;
7390                 }
7391               emitcode ("setb", "c");
7392             }
7393           else
7394             {
7395               // lit == (0 or 1)
7396               if (lit == 0)
7397                 {
7398                   // lit == 0, result = left
7399                   if (size && sameRegs (AOP (result), AOP (left)))
7400                     goto release;
7401                   emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7402                 }
7403               else
7404                 {
7405                   // lit == 1, result = not(left)
7406                   if (size && sameRegs (AOP (result), AOP (left)))
7407                     {
7408                       emitcode ("cpl", "%s", AOP (result)->aopu.aop_dir);
7409                       goto release;
7410                     }
7411                   else
7412                     {
7413                       emitcode ("mov", "c,%s", AOP (left)->aopu.aop_dir);
7414                       emitcode ("cpl", "c");
7415                     }
7416                 }
7417             }
7418
7419         }
7420       else
7421         {
7422           // right != literal
7423           symbol *tlbl = newiTempLabel (NULL);
7424           if (AOP_TYPE (right) == AOP_CRY)
7425             {
7426               // c = bit ^ bit;
7427               emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
7428             }
7429           else
7430             {
7431               int sizer = AOP_SIZE (right);
7432               // c = bit ^ val
7433               // if val>>1 != 0, result = 1
7434               emitcode ("setb", "c");
7435               while (sizer)
7436                 {
7437                   MOVA (aopGet (AOP (right), sizer - 1, FALSE, FALSE, NULL));
7438                   if (sizer == 1)
7439                     // test the msb of the lsb
7440                     emitcode ("anl", "a,#!constbyte",0xfe);
7441                   emitcode ("jnz", "!tlabel", tlbl->key + 100);
7442                   sizer--;
7443                 }
7444               // val = (0,1)
7445               emitcode ("rrc", "a");
7446             }
7447           emitcode ("jnb", "%s,!tlabel", AOP (left)->aopu.aop_dir, (tlbl->key + 100));
7448           emitcode ("cpl", "c");
7449           emitcode ("", "!tlabeldef", (tlbl->key + 100));
7450         }
7451       // bit = c
7452       // val = c
7453       if (size)
7454         outBitC (result);
7455       // if(bit | ...)
7456       else if ((AOP_TYPE (result) == AOP_CRY) && ifx)
7457         genIfxJump (ifx, "c");
7458       goto release;
7459     }
7460
7461   /* if left is same as result */
7462   if (sameRegs (AOP (result), AOP (left)))
7463     {
7464       for (; size--; offset++)
7465         {
7466           if (AOP_TYPE (right) == AOP_LIT)
7467             {
7468               bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL);
7469               if (bytelit == 0x00L)
7470                 {
7471                   /* dummy read of volatile operand */
7472                   if (isOperandVolatile (left, FALSE))
7473                     MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7474                   else
7475                     continue;
7476                 }
7477               else if (IS_AOP_PREG (left))
7478                 {
7479                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7480                   emitcode ("xrl", "a,%s",
7481                             aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7482                   aopPut (AOP (result), "a", offset);
7483                 }
7484               else
7485                 {
7486                   emitcode ("xrl", "%s,%s",
7487                             aopGet (AOP (left), offset, FALSE, TRUE, NULL),
7488                             aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7489                 }
7490             }
7491           else
7492             {
7493               if (AOP_TYPE (left) == AOP_ACC)
7494                 emitcode ("xrl", "a,%s",
7495                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7496               else
7497                 {
7498                   MOVA (aopGet (AOP (right), offset, FALSE, FALSE, NULL));
7499                   if (IS_AOP_PREG (left))
7500                     {
7501                       emitcode ("xrl", "a,%s",
7502                                 aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7503                       aopPut (AOP (result), "a", offset);
7504                     }
7505                   else
7506                     emitcode ("xrl", "%s,a",
7507                            aopGet (AOP (left), offset, FALSE, TRUE, DP2_RESULT_REG));
7508                 }
7509             }
7510         }
7511     }
7512   else
7513     {
7514       // left & result in different registers
7515       if (AOP_TYPE (result) == AOP_CRY)
7516         {
7517           // result = bit
7518           // if(size), result in bit
7519           // if(!size && ifx), conditional oper: if(left ^ right)
7520           symbol *tlbl = newiTempLabel (NULL);
7521           int sizer = max (AOP_SIZE (left), AOP_SIZE (right));
7522
7523           if (size)
7524             emitcode ("setb", "c");
7525           while (sizer--)
7526             {
7527               if ((AOP_TYPE (right) == AOP_LIT) &&
7528                   (((lit >> (offset * 8)) & 0x0FFL) == 0x00L))
7529                 {
7530                   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7531                 }
7532               else
7533                 {
7534                   if (AOP_TYPE(right)==AOP_REG && AOP_TYPE(left)==AOP_ACC) {
7535                     emitcode ("xrl", "a,%s",
7536                               aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7537                   } else {
7538                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7539                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7540                       {
7541                           emitcode("mov", "b,a");
7542                           rOp = "b";
7543                       }
7544
7545                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7546                       emitcode ("xrl", "a,%s", rOp);
7547                   }
7548                 }
7549               emitcode ("jnz", "!tlabel", tlbl->key + 100);
7550               offset++;
7551             }
7552           if (size)
7553             {
7554               CLRC;
7555               emitcode ("", "!tlabeldef", tlbl->key + 100);
7556               outBitC (result);
7557             }
7558           else if (ifx)
7559             jmpTrueOrFalse (ifx, tlbl);
7560         }
7561       else
7562         {
7563         for (; (size--); offset++)
7564           {
7565             // normal case
7566             // result = left & right
7567             if (AOP_TYPE (right) == AOP_LIT)
7568               {
7569                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
7570                   {
7571                     aopPut (AOP (result),
7572                             aopGet (AOP (left), offset, FALSE, FALSE, NULL),
7573                             offset);
7574                     continue;
7575                   }
7576                 D (emitcode (";", "better literal XOR."););
7577                 MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7578                 emitcode ("xrl", "a, %s",
7579                           aopGet (AOP (right), offset, FALSE, FALSE, DP2_RESULT_REG));
7580               }
7581             else
7582               {
7583                 // faster than result <- left, anl result,right
7584                 // and better if result is SFR
7585                 if (AOP_TYPE (left) == AOP_ACC)
7586                   {
7587                     emitcode ("xrl", "a,%s",
7588                               aopGet (AOP (right), offset,
7589                                       FALSE, FALSE, DP2_RESULT_REG));
7590                   }
7591                 else
7592                   {
7593                       char *rOp = aopGet (AOP (right), offset, FALSE, FALSE, NULL);
7594                       if (!strcmp(rOp, "a") || !strcmp(rOp, "acc"))
7595                       {
7596                           emitcode("mov", "b,a");
7597                           rOp = "b";
7598                       }
7599
7600                       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7601                       emitcode ("xrl", "a,%s", rOp);
7602                   }
7603               }
7604             aopPut (AOP (result), "a", offset);
7605           }
7606         }
7607
7608     }
7609
7610 release:
7611   freeAsmop (left, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7612   freeAsmop (right, NULL, ic, (RESULTONSTACK (ic) ? FALSE : TRUE));
7613   freeAsmop (result, NULL, ic, TRUE);
7614 }
7615
7616 /*-----------------------------------------------------------------*/
7617 /* genInline - write the inline code out                           */
7618 /*-----------------------------------------------------------------*/
7619 static void
7620 genInline (iCode * ic)
7621 {
7622   char *buffer, *bp, *bp1;
7623
7624   D (emitcode (";", "genInline "); );
7625
7626   _G.inLine += (!options.asmpeep);
7627
7628   buffer = Safe_strdup(IC_INLINE(ic));
7629   bp = buffer;
7630   bp1 = buffer;
7631
7632   /* emit each line as a code */
7633   while (*bp)
7634     {
7635       if (*bp == '\n')
7636         {
7637           *bp++ = '\0';
7638           emitcode (bp1, "");
7639           bp1 = bp;
7640         }
7641       else
7642         {
7643           if (*bp == ':')
7644             {
7645               bp++;
7646               *bp = '\0';
7647               bp++;
7648               emitcode (bp1, "");
7649               bp1 = bp;
7650             }
7651           else
7652             bp++;
7653         }
7654     }
7655   if (bp1 != bp)
7656     emitcode (bp1, "");
7657   /*     emitcode("",buffer); */
7658   _G.inLine -= (!options.asmpeep);
7659 }
7660
7661 /*-----------------------------------------------------------------*/
7662 /* genRRC - rotate right with carry                                */
7663 /*-----------------------------------------------------------------*/
7664 static void
7665 genRRC (iCode * ic)
7666 {
7667   operand *left, *result;
7668   int     size, offset;
7669
7670   D (emitcode (";", "genRRC "););
7671
7672   /* rotate right with carry */
7673   left = IC_LEFT (ic);
7674   result = IC_RESULT (ic);
7675   aopOp (left, ic, FALSE, FALSE);
7676   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7677
7678   /* move it to the result */
7679   size = AOP_SIZE (result);
7680   offset = size - 1;
7681   CLRC;
7682
7683   _startLazyDPSEvaluation ();
7684   while (size--)
7685     {
7686       MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
7687       emitcode ("rrc", "a");
7688       if (AOP_SIZE (result) > 1)
7689         aopPut (AOP (result), "a", offset--);
7690     }
7691   _endLazyDPSEvaluation ();
7692
7693   /* now we need to put the carry into the
7694      highest order byte of the result */
7695   if (AOP_SIZE (result) > 1)
7696     {
7697       MOVA (aopGet (AOP (result), AOP_SIZE (result) - 1, FALSE, FALSE, NULL));
7698     }
7699   emitcode ("mov", "acc.7,c");
7700   aopPut (AOP (result), "a", AOP_SIZE (result) - 1);
7701   freeAsmop (left, NULL, ic, TRUE);
7702   freeAsmop (result, NULL, ic, TRUE);
7703 }
7704
7705 /*-----------------------------------------------------------------*/
7706 /* genRLC - generate code for rotate left with carry               */
7707 /*-----------------------------------------------------------------*/
7708 static void
7709 genRLC (iCode * ic)
7710 {
7711   operand *left, *result;
7712   int size, offset;
7713   char *l;
7714
7715   D (emitcode (";", "genRLC "););
7716
7717   /* rotate right with carry */
7718   left = IC_LEFT (ic);
7719   result = IC_RESULT (ic);
7720   aopOp (left, ic, FALSE, FALSE);
7721   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7722
7723   /* move it to the result */
7724   size = AOP_SIZE (result);
7725   offset = 0;
7726   if (size--)
7727     {
7728       l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7729       MOVA (l);
7730       emitcode ("add", "a,acc");
7731       if (AOP_SIZE (result) > 1)
7732         {
7733           aopPut (AOP (result), "a", offset++);
7734         }
7735
7736       _startLazyDPSEvaluation ();
7737       while (size--)
7738         {
7739           l = aopGet (AOP (left), offset, FALSE, FALSE, NULL);
7740           MOVA (l);
7741           emitcode ("rlc", "a");
7742           if (AOP_SIZE (result) > 1)
7743             aopPut (AOP (result), "a", offset++);
7744         }
7745       _endLazyDPSEvaluation ();
7746     }
7747   /* now we need to put the carry into the
7748      highest order byte of the result */
7749   if (AOP_SIZE (result) > 1)
7750     {
7751       l = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
7752       MOVA (l);
7753     }
7754   emitcode ("mov", "acc.0,c");
7755   aopPut (AOP (result), "a", 0);
7756   freeAsmop (left, NULL, ic, TRUE);
7757   freeAsmop (result, NULL, ic, TRUE);
7758 }
7759
7760 /*-----------------------------------------------------------------*/
7761 /* genGetHbit - generates code get highest order bit               */
7762 /*-----------------------------------------------------------------*/
7763 static void
7764 genGetHbit (iCode * ic)
7765 {
7766   operand *left, *result;
7767   left = IC_LEFT (ic);
7768   result = IC_RESULT (ic);
7769   aopOp (left, ic, FALSE, FALSE);
7770   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7771
7772   D (emitcode (";", "genGetHbit "););
7773
7774   /* get the highest order byte into a */
7775   MOVA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE, FALSE, NULL));
7776   if (AOP_TYPE (result) == AOP_CRY)
7777     {
7778       emitcode ("rlc", "a");
7779       outBitC (result);
7780     }
7781   else
7782     {
7783       emitcode ("rl", "a");
7784       emitcode ("anl", "a,#1");
7785       outAcc (result);
7786     }
7787
7788
7789   freeAsmop (left, NULL, ic, TRUE);
7790   freeAsmop (result, NULL, ic, TRUE);
7791 }
7792
7793 /*-----------------------------------------------------------------*/
7794 /* genSwap - generates code to swap nibbles or bytes               */
7795 /*-----------------------------------------------------------------*/
7796 static void
7797 genSwap (iCode * ic)
7798 {
7799   operand *left, *result;
7800
7801   D(emitcode (";     genSwap",""));
7802
7803   left = IC_LEFT (ic);
7804   result = IC_RESULT (ic);
7805   aopOp (left, ic, FALSE, FALSE);
7806   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
7807
7808   _startLazyDPSEvaluation ();
7809   switch (AOP_SIZE (left))
7810     {
7811     case 1: /* swap nibbles in byte */
7812       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7813       emitcode ("swap", "a");
7814       aopPut (AOP (result), "a", 0);
7815       break;
7816     case 2: /* swap bytes in word */
7817       if (AOP_TYPE(left) == AOP_REG && sameRegs(AOP(left), AOP(result)))
7818         {
7819           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7820           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7821           aopPut (AOP (result), "a", 1);
7822         }
7823       else if (operandsEqu (left, result))
7824         {
7825           char * reg = "a";
7826           MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
7827           if (AOP_NEEDSACC (left) || AOP_NEEDSACC (result))
7828             {
7829               emitcode ("mov", "b,a");
7830               reg = "b";
7831               _G.bInUse=1;
7832             }
7833           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7834           aopPut (AOP (result), reg, 1);
7835           _G.bInUse=0;
7836         }
7837       else
7838         {
7839           aopPut (AOP (result), aopGet (AOP (left), 1, FALSE, FALSE, NULL), 0);
7840           aopPut (AOP (result), aopGet (AOP (left), 0, FALSE, FALSE, NULL), 1);
7841         }
7842       break;
7843     default:
7844       wassertl(FALSE, "unsupported SWAP operand size");
7845     }
7846   _endLazyDPSEvaluation ();
7847
7848   freeAsmop (left, NULL, ic, TRUE);
7849   freeAsmop (result, NULL, ic, TRUE);
7850 }
7851
7852 /*-----------------------------------------------------------------*/
7853 /* AccRol - rotate left accumulator by known count                 */
7854 /*-----------------------------------------------------------------*/
7855 static void
7856 AccRol (int shCount)
7857 {
7858   shCount &= 0x0007;            // shCount : 0..7
7859
7860   switch (shCount)
7861     {
7862     case 0:
7863       break;
7864     case 1:
7865       emitcode ("rl", "a");
7866       break;
7867     case 2:
7868       emitcode ("rl", "a");
7869       emitcode ("rl", "a");
7870       break;
7871     case 3:
7872       emitcode ("swap", "a");
7873       emitcode ("rr", "a");
7874       break;
7875     case 4:
7876       emitcode ("swap", "a");
7877       break;
7878     case 5:
7879       emitcode ("swap", "a");
7880       emitcode ("rl", "a");
7881       break;
7882     case 6:
7883       emitcode ("rr", "a");
7884       emitcode ("rr", "a");
7885       break;
7886     case 7:
7887       emitcode ("rr", "a");
7888       break;
7889     }
7890 }
7891
7892 /*-----------------------------------------------------------------*/
7893 /* AccLsh - left shift accumulator by known count                  */
7894 /*-----------------------------------------------------------------*/
7895 static void
7896 AccLsh (int shCount)
7897 {
7898   if (shCount != 0)
7899     {
7900       if (shCount == 1)
7901         emitcode ("add", "a,acc");
7902       else if (shCount == 2)
7903         {
7904           emitcode ("add", "a,acc");
7905           emitcode ("add", "a,acc");
7906         }
7907       else
7908         {
7909           /* rotate left accumulator */
7910           AccRol (shCount);
7911           /* and kill the lower order bits */
7912           emitcode ("anl", "a,#!constbyte", SLMask[shCount]);
7913         }
7914     }
7915 }
7916
7917 /*-----------------------------------------------------------------*/
7918 /* AccRsh - right shift accumulator by known count                 */
7919 /*-----------------------------------------------------------------*/
7920 static void
7921 AccRsh (int shCount)
7922 {
7923   if (shCount != 0)
7924     {
7925       if (shCount == 1)
7926         {
7927           CLRC;
7928           emitcode ("rrc", "a");
7929         }
7930       else
7931         {
7932           /* rotate right accumulator */
7933           AccRol (8 - shCount);
7934           /* and kill the higher order bits */
7935           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7936         }
7937     }
7938 }
7939
7940 #ifdef BETTER_LITERAL_SHIFT
7941 /*-----------------------------------------------------------------*/
7942 /* AccSRsh - signed right shift accumulator by known count                 */
7943 /*-----------------------------------------------------------------*/
7944 static void
7945 AccSRsh (int shCount)
7946 {
7947   symbol *tlbl;
7948   if (shCount != 0)
7949     {
7950       if (shCount == 1)
7951         {
7952           emitcode ("mov", "c,acc.7");
7953           emitcode ("rrc", "a");
7954         }
7955       else if (shCount == 2)
7956         {
7957           emitcode ("mov", "c,acc.7");
7958           emitcode ("rrc", "a");
7959           emitcode ("mov", "c,acc.7");
7960           emitcode ("rrc", "a");
7961         }
7962       else
7963         {
7964           tlbl = newiTempLabel (NULL);
7965           /* rotate right accumulator */
7966           AccRol (8 - shCount);
7967           /* and kill the higher order bits */
7968           emitcode ("anl", "a,#!constbyte", SRMask[shCount]);
7969           emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
7970           emitcode ("orl", "a,#!constbyte",
7971                     (unsigned char) ~SRMask[shCount]);
7972           emitcode ("", "!tlabeldef", tlbl->key + 100);
7973         }
7974     }
7975 }
7976 #endif
7977
7978 #ifdef BETTER_LITERAL_SHIFT
7979 /*-----------------------------------------------------------------*/
7980 /* shiftR1Left2Result - shift right one byte from left to result   */
7981 /*-----------------------------------------------------------------*/
7982 static void
7983 shiftR1Left2Result (operand * left, int offl,
7984                     operand * result, int offr,
7985                     int shCount, int sign)
7986 {
7987   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
7988   /* shift right accumulator */
7989   if (sign)
7990     AccSRsh (shCount);
7991   else
7992     AccRsh (shCount);
7993   aopPut (AOP (result), "a", offr);
7994 }
7995 #endif
7996
7997 #ifdef BETTER_LITERAL_SHIFT
7998 /*-----------------------------------------------------------------*/
7999 /* shiftL1Left2Result - shift left one byte from left to result    */
8000 /*-----------------------------------------------------------------*/
8001 static void
8002 shiftL1Left2Result (operand * left, int offl,
8003                     operand * result, int offr, int shCount)
8004 {
8005   MOVA(aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8006   /* shift left accumulator */
8007   AccLsh (shCount);
8008   aopPut (AOP (result), "a", offr);
8009 }
8010 #endif
8011
8012 #ifdef BETTER_LITERAL_SHIFT
8013 /*-----------------------------------------------------------------*/
8014 /* movLeft2Result - move byte from left to result                  */
8015 /*-----------------------------------------------------------------*/
8016 static void
8017 movLeft2Result (operand * left, int offl,
8018                 operand * result, int offr, int sign)
8019 {
8020   char *l;
8021   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
8022   {
8023       l = aopGet (AOP (left), offl, FALSE, FALSE, NULL);
8024
8025       if (*l == '@' && (IS_AOP_PREG (result)))
8026       {
8027           emitcode ("mov", "a,%s", l);
8028           aopPut (AOP (result), "a", offr);
8029       }
8030       else
8031       {
8032           if (!sign)
8033           {
8034             aopPut (AOP (result), l, offr);
8035           }
8036           else
8037             {
8038               /* MSB sign in acc.7 ! */
8039               if (getDataSize (left) == offl + 1)
8040                 {
8041                   emitcode ("mov", "a,%s", l);
8042                   aopPut (AOP (result), "a", offr);
8043                 }
8044             }
8045       }
8046   }
8047 }
8048 #endif
8049
8050 #ifdef BETTER_LITERAL_SHIFT
8051 /*-----------------------------------------------------------------*/
8052 /* AccAXRrl1 - right rotate c->a:x->c by 1                         */
8053 /*-----------------------------------------------------------------*/
8054 static void
8055 AccAXRrl1 (char *x)
8056 {
8057   emitcode ("rrc", "a");
8058   emitcode ("xch", "a,%s", x);
8059   emitcode ("rrc", "a");
8060   emitcode ("xch", "a,%s", x);
8061 }
8062 #endif
8063
8064 #ifdef BETTER_LITERAL_SHIFT
8065 //REMOVE ME!!!
8066 /*-----------------------------------------------------------------*/
8067 /* AccAXLrl1 - left rotate c<-a:x<-c by 1                          */
8068 /*-----------------------------------------------------------------*/
8069 static void
8070 AccAXLrl1 (char *x)
8071 {
8072   emitcode ("xch", "a,%s", x);
8073   emitcode ("rlc", "a");
8074   emitcode ("xch", "a,%s", x);
8075   emitcode ("rlc", "a");
8076 }
8077 #endif
8078
8079 #ifdef BETTER_LITERAL_SHIFT
8080 /*-----------------------------------------------------------------*/
8081 /* AccAXLsh1 - left shift a:x<-0 by 1                              */
8082 /*-----------------------------------------------------------------*/
8083 static void
8084 AccAXLsh1 (char *x)
8085 {
8086   emitcode ("xch", "a,%s", x);
8087   emitcode ("add", "a,acc");
8088   emitcode ("xch", "a,%s", x);
8089   emitcode ("rlc", "a");
8090 }
8091 #endif
8092
8093 #ifdef BETTER_LITERAL_SHIFT
8094 /*-----------------------------------------------------------------*/
8095 /* AccAXLsh - left shift a:x by known count (0..7)                 */
8096 /*-----------------------------------------------------------------*/
8097 static void
8098 AccAXLsh (char *x, int shCount)
8099 {
8100   switch (shCount)
8101     {
8102     case 0:
8103       break;
8104     case 1:
8105       AccAXLsh1 (x);
8106       break;
8107     case 2:
8108       AccAXLsh1 (x);
8109       AccAXLsh1 (x);
8110       break;
8111     case 3:
8112     case 4:
8113     case 5:                     // AAAAABBB:CCCCCDDD
8114
8115       AccRol (shCount);         // BBBAAAAA:CCCCCDDD
8116
8117       emitcode ("anl", "a,#!constbyte",
8118                 SLMask[shCount]);       // BBB00000:CCCCCDDD
8119
8120       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBB00000
8121
8122       AccRol (shCount);         // DDDCCCCC:BBB00000
8123
8124       emitcode ("xch", "a,%s", x);      // BBB00000:DDDCCCCC
8125
8126       emitcode ("xrl", "a,%s", x);      // (BBB^DDD)CCCCC:DDDCCCCC
8127
8128       emitcode ("xch", "a,%s", x);      // DDDCCCCC:(BBB^DDD)CCCCC
8129
8130       emitcode ("anl", "a,#!constbyte",
8131                 SLMask[shCount]);       // DDD00000:(BBB^DDD)CCCCC
8132
8133       emitcode ("xch", "a,%s", x);      // (BBB^DDD)CCCCC:DDD00000
8134
8135       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:DDD00000
8136
8137       break;
8138     case 6:                     // AAAAAABB:CCCCCCDD
8139       emitcode ("anl", "a,#!constbyte",
8140                 SRMask[shCount]);       // 000000BB:CCCCCCDD
8141       emitcode ("mov", "c,acc.0");      // c = B
8142       emitcode ("xch", "a,%s", x);      // CCCCCCDD:000000BB
8143 #if 0
8144       AccAXRrl1 (x);            // BCCCCCCD:D000000B
8145       AccAXRrl1 (x);            // BBCCCCCC:DD000000
8146 #else
8147       emitcode("rrc","a");
8148       emitcode("xch","a,%s", x);
8149       emitcode("rrc","a");
8150       emitcode("mov","c,acc.0"); //<< get correct bit
8151       emitcode("xch","a,%s", x);
8152
8153       emitcode("rrc","a");
8154       emitcode("xch","a,%s", x);
8155       emitcode("rrc","a");
8156       emitcode("xch","a,%s", x);
8157 #endif
8158       break;
8159     case 7:                     // a:x <<= 7
8160
8161       emitcode ("anl", "a,#!constbyte",
8162                 SRMask[shCount]);       // 0000000B:CCCCCCCD
8163
8164       emitcode ("mov", "c,acc.0");      // c = B
8165
8166       emitcode ("xch", "a,%s", x);      // CCCCCCCD:0000000B
8167
8168       AccAXRrl1 (x);            // BCCCCCCC:D0000000
8169
8170       break;
8171     default:
8172       break;
8173     }
8174 }
8175 #endif
8176
8177 #ifdef BETTER_LITERAL_SHIFT
8178 //REMOVE ME!!!
8179 /*-----------------------------------------------------------------*/
8180 /* AccAXRsh - right shift a:x known count (0..7)                   */
8181 /*-----------------------------------------------------------------*/
8182 static void
8183 AccAXRsh (char *x, int shCount)
8184 {
8185   switch (shCount)
8186     {
8187     case 0:
8188       break;
8189     case 1:
8190       CLRC;
8191       AccAXRrl1 (x);            // 0->a:x
8192
8193       break;
8194     case 2:
8195       CLRC;
8196       AccAXRrl1 (x);            // 0->a:x
8197
8198       CLRC;
8199       AccAXRrl1 (x);            // 0->a:x
8200
8201       break;
8202     case 3:
8203     case 4:
8204     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8205
8206       AccRol (8 - shCount);     // BBBAAAAA:DDDCCCCC
8207
8208       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8209
8210       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8211
8212       emitcode ("anl", "a,#!constbyte",
8213                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8214
8215       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8216
8217       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8218
8219       emitcode ("anl", "a,#!constbyte",
8220                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8221
8222       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8223
8224       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8225
8226       emitcode ("xch", "a,%s", x);      // 000AAAAA:BBBCCCCC
8227
8228       break;
8229     case 6:                     // AABBBBBB:CCDDDDDD
8230
8231       emitcode ("mov", "c,acc.7");
8232       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8233
8234       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8235
8236       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8237
8238       emitcode ("anl", "a,#!constbyte",
8239                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8240
8241       break;
8242     case 7:                     // ABBBBBBB:CDDDDDDD
8243
8244       emitcode ("mov", "c,acc.7");      // c = A
8245
8246       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8247
8248       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8249
8250       emitcode ("anl", "a,#!constbyte",
8251                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8252
8253       break;
8254     default:
8255       break;
8256     }
8257 }
8258 #endif
8259
8260 #ifdef BETTER_LITERAL_SHIFT
8261 /*-----------------------------------------------------------------*/
8262 /* AccAXRshS - right shift signed a:x known count (0..7)           */
8263 /*-----------------------------------------------------------------*/
8264 static void
8265 AccAXRshS (char *x, int shCount)
8266 {
8267   symbol *tlbl;
8268   switch (shCount)
8269     {
8270     case 0:
8271       break;
8272     case 1:
8273       emitcode ("mov", "c,acc.7");
8274       AccAXRrl1 (x);            // s->a:x
8275
8276       break;
8277     case 2:
8278       emitcode ("mov", "c,acc.7");
8279       AccAXRrl1 (x);            // s->a:x
8280
8281       emitcode ("mov", "c,acc.7");
8282       AccAXRrl1 (x);            // s->a:x
8283
8284       break;
8285     case 3:
8286     case 4:
8287     case 5:                     // AAAAABBB:CCCCCDDD = a:x
8288
8289       tlbl = newiTempLabel (NULL);
8290       AccRol (8 - shCount);     // BBBAAAAA:CCCCCDDD
8291
8292       emitcode ("xch", "a,%s", x);      // CCCCCDDD:BBBAAAAA
8293
8294       AccRol (8 - shCount);     // DDDCCCCC:BBBAAAAA
8295
8296       emitcode ("anl", "a,#!constbyte",
8297                 SRMask[shCount]);       // 000CCCCC:BBBAAAAA
8298
8299       emitcode ("xrl", "a,%s", x);      // BBB(CCCCC^AAAAA):BBBAAAAA
8300
8301       emitcode ("xch", "a,%s", x);      // BBBAAAAA:BBB(CCCCC^AAAAA)
8302
8303       emitcode ("anl", "a,#!constbyte",
8304                 SRMask[shCount]);       // 000AAAAA:BBB(CCCCC^AAAAA)
8305
8306       emitcode ("xch", "a,%s", x);      // BBB(CCCCC^AAAAA):000AAAAA
8307
8308       emitcode ("xrl", "a,%s", x);      // BBBCCCCC:000AAAAA
8309
8310       emitcode ("xch", "a,%s", x);      // 000SAAAA:BBBCCCCC
8311
8312       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8313       emitcode ("orl", "a,#!constbyte",
8314                 (unsigned char) ~SRMask[shCount]);      // 111AAAAA:BBBCCCCC
8315
8316       emitcode ("", "!tlabeldef", tlbl->key + 100);
8317       break;                    // SSSSAAAA:BBBCCCCC
8318
8319     case 6:                     // AABBBBBB:CCDDDDDD
8320
8321       tlbl = newiTempLabel (NULL);
8322       emitcode ("mov", "c,acc.7");
8323       AccAXLrl1 (x);            // ABBBBBBC:CDDDDDDA
8324
8325       AccAXLrl1 (x);            // BBBBBBCC:DDDDDDAA
8326
8327       emitcode ("xch", "a,%s", x);      // DDDDDDAA:BBBBBBCC
8328
8329       emitcode ("anl", "a,#!constbyte",
8330                 SRMask[shCount]);       // 000000AA:BBBBBBCC
8331
8332       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8333       emitcode ("orl", "a,#!constbyte",
8334                 (unsigned char) ~SRMask[shCount]);      // 111111AA:BBBBBBCC
8335
8336       emitcode ("", "!tlabeldef", tlbl->key + 100);
8337       break;
8338     case 7:                     // ABBBBBBB:CDDDDDDD
8339
8340       tlbl = newiTempLabel (NULL);
8341       emitcode ("mov", "c,acc.7");      // c = A
8342
8343       AccAXLrl1 (x);            // BBBBBBBC:DDDDDDDA
8344
8345       emitcode ("xch", "a,%s", x);      // DDDDDDDA:BBBBBBCC
8346
8347       emitcode ("anl", "a,#!constbyte",
8348                 SRMask[shCount]);       // 0000000A:BBBBBBBC
8349
8350       emitcode ("jnb", "acc.%d,!tlabel", 7 - shCount, tlbl->key + 100);
8351       emitcode ("orl", "a,#!constbyte",
8352                 (unsigned char) ~SRMask[shCount]);      // 1111111A:BBBBBBBC
8353
8354       emitcode ("", "!tlabeldef", tlbl->key + 100);
8355       break;
8356     default:
8357       break;
8358     }
8359 }
8360 #endif
8361
8362 #ifdef BETTER_LITERAL_SHIFT
8363 static void
8364 _loadLeftIntoAx(char    **lsb,
8365                 operand *left,
8366                 operand *result,
8367                 int     offl,
8368                 int     offr)
8369 {
8370   // Get the initial value from left into a pair of registers.
8371   // MSB must be in A, LSB can be any register.
8372   //
8373   // If the result is held in registers, it is an optimization
8374   // if the LSB can be held in the register which will hold the,
8375   // result LSB since this saves us from having to copy it into
8376   // the result following AccAXLsh.
8377   //
8378   // If the result is addressed indirectly, this is not a gain.
8379   if (AOP_NEEDSACC(result))
8380   {
8381        char *leftByte;
8382
8383        _startLazyDPSEvaluation();
8384       if (AOP_TYPE(left) == AOP_DPTR2)
8385        {
8386            // Get MSB in A.
8387            MOVA(aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL));
8388            // get LSB in DP2_RESULT_REG.
8389            leftByte = aopGet(AOP(left), offl, FALSE, FALSE, DP2_RESULT_REG);
8390            assert(!strcmp(leftByte, DP2_RESULT_REG));
8391        }
8392        else
8393        {
8394            // get LSB into DP2_RESULT_REG
8395            leftByte = aopGet (AOP(left), offl, FALSE, FALSE, NULL);
8396            if (strcmp(leftByte, DP2_RESULT_REG))
8397            {
8398                TR_AP("#7");
8399                emitcode("mov","%s,%s", DP2_RESULT_REG, leftByte);
8400            }
8401            // And MSB in A.
8402            leftByte = aopGet(AOP(left), offl + MSB16, FALSE, FALSE, NULL);
8403            assert(strcmp(leftByte, DP2_RESULT_REG));
8404            MOVA(leftByte);
8405        }
8406        _endLazyDPSEvaluation();
8407        *lsb = DP2_RESULT_REG;
8408   }
8409   else
8410   {
8411       if (sameRegs (AOP (result), AOP (left)) &&
8412         ((offl + MSB16) == offr))
8413       {
8414           /* don't crash result[offr] */
8415           MOVA(aopGet(AOP(left), offl, FALSE, FALSE, NULL));
8416           emitcode ("xch", "a,%s",
8417                     aopGet(AOP(left), offl + MSB16, FALSE, FALSE, DP2_RESULT_REG));
8418       }
8419       else
8420       {
8421           movLeft2Result (left, offl, result, offr, 0);
8422           MOVA (aopGet (AOP (left), offl + MSB16, FALSE, FALSE, NULL));
8423       }
8424       *lsb = aopGet(AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG);
8425       assert(strcmp(*lsb,"a"));
8426   }
8427 }
8428
8429 static void
8430 _storeAxResults(char    *lsb,
8431                 operand *result,
8432                 int     offr)
8433 {
8434   _startLazyDPSEvaluation();
8435   if (AOP_NEEDSACC(result))
8436   {
8437       /* We have to explicitly update the result LSB.
8438        */
8439       emitcode("xch","a,%s", lsb);
8440       aopPut(AOP(result), "a", offr);
8441       emitcode("mov","a,%s", lsb);
8442   }
8443   if (getDataSize (result) > 1)
8444   {
8445       aopPut (AOP (result), "a", offr + MSB16);
8446   }
8447   _endLazyDPSEvaluation();
8448 }
8449
8450 /*-----------------------------------------------------------------*/
8451 /* shiftL2Left2Result - shift left two bytes from left to result   */
8452 /*-----------------------------------------------------------------*/
8453 static void
8454 shiftL2Left2Result (operand * left, int offl,
8455                     operand * result, int offr, int shCount)
8456 {
8457   char *lsb;
8458
8459   _loadLeftIntoAx(&lsb, left, result, offl, offr);
8460
8461   AccAXLsh (lsb, shCount);
8462
8463   _storeAxResults(lsb, result, offr);
8464 }
8465 #endif
8466
8467 #ifdef BETTER_LITERAL_SHIFT
8468 /*-----------------------------------------------------------------*/
8469 /* shiftR2Left2Result - shift right two bytes from left to result  */
8470 /*-----------------------------------------------------------------*/
8471 static void
8472 shiftR2Left2Result (operand * left, int offl,
8473                     operand * result, int offr,
8474                     int shCount, int sign)
8475 {
8476   char *lsb;
8477
8478   _loadLeftIntoAx(&lsb, left, result, offl, offr);
8479
8480   /* a:x >> shCount (x = lsb(result)) */
8481   if (sign)
8482   {
8483      AccAXRshS(lsb, shCount);
8484   }
8485   else
8486   {
8487     AccAXRsh(lsb, shCount);
8488   }
8489
8490   _storeAxResults(lsb, result, offr);
8491 }
8492 #endif
8493
8494 /*-----------------------------------------------------------------*/
8495 /* shiftLLeftOrResult - shift left one byte from left, or to result */
8496 /*-----------------------------------------------------------------*/
8497 static void
8498 shiftLLeftOrResult (operand * left, int offl,
8499                     operand * result, int offr, int shCount)
8500 {
8501   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8502   /* shift left accumulator */
8503   AccLsh (shCount);
8504   /* or with result */
8505   emitcode ("orl", "a,%s",
8506             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
8507   /* back to result */
8508   aopPut (AOP (result), "a", offr);
8509 }
8510
8511 #if 0
8512 //REMOVE ME!!!
8513 /*-----------------------------------------------------------------*/
8514 /* shiftRLeftOrResult - shift right one byte from left,or to result */
8515 /*-----------------------------------------------------------------*/
8516 static void
8517 shiftRLeftOrResult (operand * left, int offl,
8518                     operand * result, int offr, int shCount)
8519 {
8520   MOVA (aopGet (AOP (left), offl, FALSE, FALSE, NULL));
8521   /* shift right accumulator */
8522   AccRsh (shCount);
8523   /* or with result */
8524   emitcode ("orl", "a,%s",
8525             aopGet (AOP (result), offr, FALSE, FALSE, DP2_RESULT_REG));
8526   /* back to result */
8527   aopPut (AOP (result), "a", offr);
8528 }
8529 #endif
8530
8531 #ifdef BETTER_LITERAL_SHIFT
8532 /*-----------------------------------------------------------------*/
8533 /* genlshOne - left shift a one byte quantity by known count       */
8534 /*-----------------------------------------------------------------*/
8535 static void
8536 genlshOne (operand * result, operand * left, int shCount)
8537 {
8538   D (emitcode (";", "genlshOne "););
8539   shiftL1Left2Result (left, LSB, result, LSB, shCount);
8540 }
8541 #endif
8542
8543 #ifdef BETTER_LITERAL_SHIFT
8544 /*-----------------------------------------------------------------*/
8545 /* genlshTwo - left shift two bytes by known amount != 0           */
8546 /*-----------------------------------------------------------------*/
8547 static void
8548 genlshTwo (operand * result, operand * left, int shCount)
8549 {
8550   int size;
8551
8552   D (emitcode (";", "genlshTwo "););
8553
8554   size = getDataSize (result);
8555
8556   /* if shCount >= 8 */
8557   if (shCount >= 8)
8558   {
8559       shCount -= 8;
8560
8561       _startLazyDPSEvaluation();
8562
8563       if (size > 1)
8564         {
8565           if (shCount)
8566           {
8567             _endLazyDPSEvaluation();
8568             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8569             aopPut (AOP (result), zero, LSB);
8570           }
8571           else
8572           {
8573             movLeft2Result (left, LSB, result, MSB16, 0);
8574             aopPut (AOP (result), zero, LSB);
8575             _endLazyDPSEvaluation();
8576           }
8577         }
8578         else
8579         {
8580           aopPut (AOP (result), zero, LSB);
8581           _endLazyDPSEvaluation();
8582         }
8583   }
8584
8585   /*  1 <= shCount <= 7 */
8586   else
8587     {
8588       if (size == 1)
8589       {
8590         shiftL1Left2Result (left, LSB, result, LSB, shCount);
8591       }
8592       else
8593       {
8594         shiftL2Left2Result (left, LSB, result, LSB, shCount);
8595       }
8596     }
8597 }
8598 #endif
8599
8600 #if 0
8601 //REMOVE ME!!!
8602 /*-----------------------------------------------------------------*/
8603 /* shiftLLong - shift left one long from left to result            */
8604 /* offl = LSB or MSB16                                             */
8605 /*-----------------------------------------------------------------*/
8606 static void
8607 shiftLLong (operand * left, operand * result, int offr)
8608 {
8609   char *l;
8610   int size = AOP_SIZE (result);
8611
8612   if (size >= LSB + offr)
8613     {
8614       l = aopGet (AOP (left), LSB, FALSE, FALSE, NULL);
8615       MOVA (l);
8616       emitcode ("add", "a,acc");
8617       if (sameRegs (AOP (left), AOP (result)) &&
8618           size >= MSB16 + offr && offr != LSB)
8619         emitcode ("xch", "a,%s",
8620                   aopGet (AOP (left), LSB + offr, FALSE, FALSE, DP2_RESULT_REG));
8621       else
8622         aopPut (AOP (result), "a", LSB + offr);
8623     }
8624
8625   if (size >= MSB16 + offr)
8626     {
8627       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB16 + offr && offr != LSB))
8628         {
8629           MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, TRUE));
8630         }
8631       emitcode ("rlc", "a");
8632       if (sameRegs (AOP (left), AOP (result)) &&
8633           size >= MSB24 + offr && offr != LSB)
8634         emitcode ("xch", "a,%s",
8635                   aopGet (AOP (left), MSB16 + offr, FALSE, FALSE, DP2_RESULT_REG));
8636       else
8637         aopPut (AOP (result), "a", MSB16 + offr);
8638     }
8639
8640   if (size >= MSB24 + offr)
8641     {
8642       if (!(sameRegs (AOP (left), AOP (left)) && size >= MSB24 + offr && offr != LSB))
8643         {
8644           MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
8645         }
8646       emitcode ("rlc", "a");
8647       if (sameRegs (AOP (left), AOP (result)) &&
8648           size >= MSB32 + offr && offr != LSB)
8649         emitcode ("xch", "a,%s",
8650                   aopGet (AOP (left), MSB24 + offr, FALSE, FALSE, DP2_RESULT_REG));
8651       else
8652         aopPut (AOP (result), "a", MSB24 + offr);
8653     }
8654
8655   if (size > MSB32 + offr)
8656     {
8657       if (!(sameRegs (AOP (result), AOP (left)) && size >= MSB32 + offr && offr != LSB))
8658         {
8659           MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
8660         }
8661       emitcode ("rlc", "a");
8662       aopPut (AOP (result), "a", MSB32 + offr);
8663     }
8664   if (offr != LSB)
8665     aopPut (AOP (result), zero, LSB);
8666 }
8667 #endif
8668
8669 #if 0
8670 //REMOVE ME!!!
8671 /*-----------------------------------------------------------------*/
8672 /* genlshFour - shift four byte by a known amount != 0             */
8673 /*-----------------------------------------------------------------*/
8674 static void
8675 genlshFour (operand * result, operand * left, int shCount)
8676 {
8677   int size;
8678
8679   D (emitcode (";", "genlshFour ");
8680     );
8681
8682   size = AOP_SIZE (result);
8683
8684   /* if shifting more that 3 bytes */
8685   if (shCount >= 24)
8686     {
8687       shCount -= 24;
8688       if (shCount)
8689         /* lowest order of left goes to the highest
8690            order of the destination */
8691         shiftL1Left2Result (left, LSB, result, MSB32, shCount);
8692       else
8693         movLeft2Result (left, LSB, result, MSB32, 0);
8694       aopPut (AOP (result), zero, LSB);
8695       aopPut (AOP (result), zero, MSB16);
8696       aopPut (AOP (result), zero, MSB24);
8697       return;
8698     }
8699
8700   /* more than two bytes */
8701   else if (shCount >= 16)
8702     {
8703       /* lower order two bytes goes to higher order two bytes */
8704       shCount -= 16;
8705       /* if some more remaining */
8706       if (shCount)
8707         shiftL2Left2Result (left, LSB, result, MSB24, shCount);
8708       else
8709         {
8710           movLeft2Result (left, MSB16, result, MSB32, 0);
8711           movLeft2Result (left, LSB, result, MSB24, 0);
8712         }
8713       aopPut (AOP (result), zero, MSB16);
8714       aopPut (AOP (result), zero, LSB);
8715       return;
8716     }
8717
8718   /* if more than 1 byte */
8719   else if (shCount >= 8)
8720     {
8721       /* lower order three bytes goes to higher order  three bytes */
8722       shCount -= 8;
8723       if (size == 2)
8724         {
8725           if (shCount)
8726             shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8727           else
8728             movLeft2Result (left, LSB, result, MSB16, 0);
8729         }
8730       else
8731         {                       /* size = 4 */
8732           if (shCount == 0)
8733             {
8734               movLeft2Result (left, MSB24, result, MSB32, 0);
8735               movLeft2Result (left, MSB16, result, MSB24, 0);
8736               movLeft2Result (left, LSB, result, MSB16, 0);
8737               aopPut (AOP (result), zero, LSB);
8738             }
8739           else if (shCount == 1)
8740             shiftLLong (left, result, MSB16);
8741           else
8742             {
8743               shiftL2Left2Result (left, MSB16, result, MSB24, shCount);
8744               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
8745               shiftRLeftOrResult (left, LSB, result, MSB24, 8 - shCount);
8746               aopPut (AOP (result), zero, LSB);
8747             }
8748         }
8749     }
8750
8751   /* 1 <= shCount <= 7 */
8752   else if (shCount <= 2)
8753     {
8754       shiftLLong (left, result, LSB);
8755       if (shCount == 2)
8756         shiftLLong (result, result, LSB);
8757     }
8758   /* 3 <= shCount <= 7, optimize */
8759   else
8760     {
8761       shiftL2Left2Result (left, MSB24, result, MSB24, shCount);
8762       shiftRLeftOrResult (left, MSB16, result, MSB24, 8 - shCount);
8763       shiftL2Left2Result (left, LSB, result, LSB, shCount);
8764     }
8765 }
8766 #endif
8767
8768 #ifdef BETTER_LITERAL_SHIFT
8769 /*-----------------------------------------------------------------*/
8770 /* genLeftShiftLiteral - left shifting by known count              */
8771 /*-----------------------------------------------------------------*/
8772 static bool
8773 genLeftShiftLiteral (operand * left,
8774                      operand * right,
8775                      operand * result,
8776                      iCode * ic)
8777 {
8778   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
8779   int size;
8780
8781   size = getSize (operandType (result));
8782
8783   D(emitcode (";", "genLeftShiftLiteral (%d), size %d", shCount, size););
8784
8785   /* We only handle certain easy cases so far. */
8786   if ((shCount != 0)
8787    && (shCount < (size * 8))
8788    && (size != 1)
8789    && (size != 2))
8790   {
8791       D(emitcode (";", "genLeftShiftLiteral wimping out"););
8792       return FALSE;
8793   }
8794
8795   freeAsmop (right, NULL, ic, TRUE);
8796
8797   aopOp(left, ic, FALSE, FALSE);
8798   aopOp(result, ic, FALSE, AOP_USESDPTR(left));
8799
8800 #if 0 // debug spew
8801   if (IS_SYMOP(left) && OP_SYMBOL(left)->aop)
8802   {
8803         emitcode(";", "left (%s) is %d", OP_SYMBOL(left)->rname, AOP_TYPE(left));
8804         if (!IS_TRUE_SYMOP(left) && OP_SYMBOL(left)->usl.spillLoc)
8805         {
8806            emitcode(";", "\taka %s", OP_SYMBOL(left)->usl.spillLoc->rname);
8807         }
8808   }
8809   if (IS_SYMOP(result) && OP_SYMBOL(result)->aop)
8810   {
8811         emitcode(";", "result (%s) is %d", OP_SYMBOL(result)->rname, AOP_TYPE(result));
8812         if (!IS_TRUE_SYMOP(result) && OP_SYMBOL(result)->usl.spillLoc)
8813         {
8814            emitcode(";", "\taka %s", OP_SYMBOL(result)->usl.spillLoc->rname);
8815         }
8816   }
8817 #endif
8818
8819 #if VIEW_SIZE
8820   emitcode ("; shift left ", "result %d, left %d", size,
8821             AOP_SIZE (left));
8822 #endif
8823
8824   /* I suppose that the left size >= result size */
8825   if (shCount == 0)
8826   {
8827         _startLazyDPSEvaluation();
8828         while (size--)
8829         {
8830           movLeft2Result (left, size, result, size, 0);
8831         }
8832         _endLazyDPSEvaluation();
8833   }
8834   else if (shCount >= (size * 8))
8835   {
8836     _startLazyDPSEvaluation();
8837     while (size--)
8838     {
8839       aopPut (AOP (result), zero, size);
8840     }
8841     _endLazyDPSEvaluation();
8842   }
8843   else
8844   {
8845       switch (size)
8846         {
8847         case 1:
8848           genlshOne (result, left, shCount);
8849           break;
8850
8851         case 2:
8852           genlshTwo (result, left, shCount);
8853           break;
8854 #if 0
8855         case 4:
8856           genlshFour (result, left, shCount);
8857           break;
8858 #endif
8859         default:
8860           fprintf(stderr, "*** ack! mystery literal shift!\n");
8861           break;
8862         }
8863     }
8864   freeAsmop (left, NULL, ic, TRUE);
8865   freeAsmop (result, NULL, ic, TRUE);
8866   return TRUE;
8867 }
8868 #endif
8869
8870 /*-----------------------------------------------------------------*/
8871 /* genLeftShift - generates code for left shifting                 */
8872 /*-----------------------------------------------------------------*/
8873 static void
8874 genLeftShift (iCode * ic)
8875 {
8876   operand *left, *right, *result;
8877   int size, offset;
8878   char *l;
8879   symbol *tlbl, *tlbl1;
8880
8881   D (emitcode (";", "genLeftShift "););
8882
8883   right = IC_RIGHT (ic);
8884   left = IC_LEFT (ic);
8885   result = IC_RESULT (ic);
8886
8887   aopOp (right, ic, FALSE, FALSE);
8888
8889
8890 #ifdef BETTER_LITERAL_SHIFT
8891   /* if the shift count is known then do it
8892      as efficiently as possible */
8893   if (AOP_TYPE (right) == AOP_LIT)
8894     {
8895       if (genLeftShiftLiteral (left, right, result, ic))
8896       {
8897         return;
8898       }
8899     }
8900 #endif
8901
8902   /* shift count is unknown then we have to form
8903      a loop get the loop count in B : Note: we take
8904      only the lower order byte since shifting
8905      more that 32 bits make no sense anyway, ( the
8906      largest size of an object can be only 32 bits ) */
8907
8908   if (AOP_TYPE (right) == AOP_LIT)
8909   {
8910       /* Really should be handled by genLeftShiftLiteral,
8911        * but since I'm too lazy to fix that today, at least we can make
8912        * some small improvement.
8913        */
8914        emitcode("mov", "b,#!constbyte",
8915                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
8916   }
8917   else
8918   {
8919       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
8920       emitcode ("inc", "b");
8921   }
8922   freeAsmop (right, NULL, ic, TRUE);
8923   aopOp (left, ic, FALSE, FALSE);
8924   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
8925
8926   /* now move the left to the result if they are not the
8927      same */
8928   if (!sameRegs (AOP (left), AOP (result)) &&
8929       AOP_SIZE (result) > 1)
8930     {
8931
8932       size = AOP_SIZE (result);
8933       offset = 0;
8934       _startLazyDPSEvaluation ();
8935       while (size--)
8936         {
8937           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
8938           if (*l == '@' && (IS_AOP_PREG (result)))
8939             {
8940
8941               emitcode ("mov", "a,%s", l);
8942               aopPut (AOP (result), "a", offset);
8943             }
8944           else
8945             aopPut (AOP (result), l, offset);
8946           offset++;
8947         }
8948       _endLazyDPSEvaluation ();
8949     }
8950
8951   tlbl = newiTempLabel (NULL);
8952   size = AOP_SIZE (result);
8953   offset = 0;
8954   tlbl1 = newiTempLabel (NULL);
8955
8956   /* if it is only one byte then */
8957   if (size == 1)
8958     {
8959       symbol *tlbl1 = newiTempLabel (NULL);
8960
8961       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
8962       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8963       emitcode ("", "!tlabeldef", tlbl->key + 100);
8964       emitcode ("add", "a,acc");
8965       emitcode ("", "!tlabeldef", tlbl1->key + 100);
8966       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8967       aopPut (AOP (result), "a", 0);
8968       goto release;
8969     }
8970
8971   reAdjustPreg (AOP (result));
8972
8973   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
8974   emitcode ("", "!tlabeldef", tlbl->key + 100);
8975   MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8976   emitcode ("add", "a,acc");
8977   aopPut (AOP (result), "a", offset++);
8978   _startLazyDPSEvaluation ();
8979   while (--size)
8980     {
8981       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
8982       emitcode ("rlc", "a");
8983       aopPut (AOP (result), "a", offset++);
8984     }
8985   _endLazyDPSEvaluation ();
8986   reAdjustPreg (AOP (result));
8987
8988   emitcode ("", "!tlabeldef", tlbl1->key + 100);
8989   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
8990 release:
8991   freeAsmop (left, NULL, ic, TRUE);
8992   freeAsmop (result, NULL, ic, TRUE);
8993 }
8994
8995 #ifdef BETTER_LITERAL_SHIFT
8996 /*-----------------------------------------------------------------*/
8997 /* genrshOne - right shift a one byte quantity by known count      */
8998 /*-----------------------------------------------------------------*/
8999 static void
9000 genrshOne (operand * result, operand * left,
9001            int shCount, int sign)
9002 {
9003   D (emitcode (";", "genrshOne"););
9004   shiftR1Left2Result (left, LSB, result, LSB, shCount, sign);
9005 }
9006 #endif
9007
9008 #ifdef BETTER_LITERAL_SHIFT
9009 /*-----------------------------------------------------------------*/
9010 /* genrshTwo - right shift two bytes by known amount != 0          */
9011 /*-----------------------------------------------------------------*/
9012 static void
9013 genrshTwo (operand * result, operand * left,
9014            int shCount, int sign)
9015 {
9016   D (emitcode (";", "genrshTwo"););
9017
9018   /* if shCount >= 8 */
9019   if (shCount >= 8)
9020     {
9021       shCount -= 8;
9022       _startLazyDPSEvaluation();
9023       if (shCount)
9024       {
9025         shiftR1Left2Result (left, MSB16, result, LSB,
9026                             shCount, sign);
9027       }
9028       else
9029       {
9030         movLeft2Result (left, MSB16, result, LSB, sign);
9031       }
9032       addSign (result, MSB16, sign);
9033       _endLazyDPSEvaluation();
9034     }
9035
9036   /*  1 <= shCount <= 7 */
9037   else
9038   {
9039     shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
9040   }
9041 }
9042 #endif
9043
9044 /*-----------------------------------------------------------------*/
9045 /* shiftRLong - shift right one long from left to result           */
9046 /* offl = LSB or MSB16                                             */
9047 /*-----------------------------------------------------------------*/
9048 static void
9049 shiftRLong (operand * left, int offl,
9050             operand * result, int sign)
9051 {
9052   int isSameRegs=sameRegs(AOP(left),AOP(result));
9053
9054   if (isSameRegs && offl>1) {
9055     // we are in big trouble, but this shouldn't happen
9056     werror(E_INTERNAL_ERROR, __FILE__, __LINE__);
9057   }
9058
9059   MOVA (aopGet (AOP (left), MSB32, FALSE, FALSE, NULL));
9060
9061   if (offl==MSB16) {
9062     // shift is > 8
9063     if (sign) {
9064       emitcode ("rlc", "a");
9065       emitcode ("subb", "a,acc");
9066       emitcode ("xch", "a,%s",
9067                 aopGet(AOP(left), MSB32, FALSE, FALSE, DP2_RESULT_REG));
9068     } else {
9069       aopPut (AOP(result), zero, MSB32);
9070     }
9071   }
9072
9073   if (!sign) {
9074     emitcode ("clr", "c");
9075   } else {
9076     emitcode ("mov", "c,acc.7");
9077   }
9078
9079   emitcode ("rrc", "a");
9080
9081   if (isSameRegs && offl==MSB16) {
9082     emitcode ("xch",
9083               "a,%s",aopGet (AOP (left), MSB24, FALSE, FALSE, DP2_RESULT_REG));
9084   } else {
9085     aopPut (AOP (result), "a", MSB32);
9086     MOVA (aopGet (AOP (left), MSB24, FALSE, FALSE, NULL));
9087   }
9088
9089   emitcode ("rrc", "a");
9090   if (isSameRegs && offl==1) {
9091     emitcode ("xch", "a,%s",
9092               aopGet (AOP (left), MSB16, FALSE, FALSE, DP2_RESULT_REG));
9093   } else {
9094     aopPut (AOP (result), "a", MSB24);
9095     MOVA (aopGet (AOP (left), MSB16, FALSE, FALSE, NULL));
9096   }
9097   emitcode ("rrc", "a");
9098   aopPut (AOP (result), "a", MSB16 - offl);
9099
9100   if (offl == LSB)
9101     {
9102       MOVA (aopGet (AOP (left), LSB, FALSE, FALSE, NULL));
9103       emitcode ("rrc", "a");
9104       aopPut (AOP (result), "a", LSB);
9105     }
9106 }
9107
9108 /*-----------------------------------------------------------------*/
9109 /* genrshFour - shift four byte by a known amount != 0             */
9110 /*-----------------------------------------------------------------*/
9111 static void
9112 genrshFour (operand * result, operand * left,
9113             int shCount, int sign)
9114 {
9115   D (emitcode (";", "genrshFour"););
9116
9117   /* if shifting more that 3 bytes */
9118   if (shCount >= 24)
9119     {
9120       shCount -= 24;
9121       _startLazyDPSEvaluation();
9122       if (shCount)
9123         shiftR1Left2Result (left, MSB32, result, LSB, shCount, sign);
9124       else
9125         movLeft2Result (left, MSB32, result, LSB, sign);
9126       addSign (result, MSB16, sign);
9127       _endLazyDPSEvaluation();
9128     }
9129   else if (shCount >= 16)
9130     {
9131       shCount -= 16;
9132       _startLazyDPSEvaluation();
9133       if (shCount)
9134         shiftR2Left2Result (left, MSB24, result, LSB, shCount, sign);
9135       else
9136         {
9137           movLeft2Result (left, MSB24, result, LSB, 0);
9138           movLeft2Result (left, MSB32, result, MSB16, sign);
9139         }
9140       addSign (result, MSB24, sign);
9141       _endLazyDPSEvaluation();
9142     }
9143   else if (shCount >= 8)
9144     {
9145       shCount -= 8;
9146       _startLazyDPSEvaluation();
9147       if (shCount == 1)
9148         {
9149             shiftRLong (left, MSB16, result, sign);
9150         }
9151       else if (shCount == 0)
9152         {
9153           movLeft2Result (left, MSB16, result, LSB, 0);
9154           movLeft2Result (left, MSB24, result, MSB16, 0);
9155           movLeft2Result (left, MSB32, result, MSB24, sign);
9156           addSign (result, MSB32, sign);
9157         }
9158       else
9159         {
9160           shiftR2Left2Result (left, MSB16, result, LSB, shCount, 0);
9161           shiftLLeftOrResult (left, MSB32, result, MSB16, 8 - shCount);
9162           /* the last shift is signed */
9163           shiftR1Left2Result (left, MSB32, result, MSB24, shCount, sign);
9164           addSign (result, MSB32, sign);
9165         }
9166         _endLazyDPSEvaluation();
9167     }
9168   else
9169     {
9170         /* 1 <= shCount <= 7 */
9171       if (shCount <= 2)
9172         {
9173           shiftRLong (left, LSB, result, sign);
9174           if (shCount == 2)
9175             shiftRLong (result, LSB, result, sign);
9176         }
9177       else
9178         {
9179           shiftR2Left2Result (left, LSB, result, LSB, shCount, 0);
9180           shiftLLeftOrResult (left, MSB24, result, MSB16, 8 - shCount);
9181           shiftR2Left2Result (left, MSB24, result, MSB24, shCount, sign);
9182         }
9183     }
9184 }
9185
9186 #ifdef BETTER_LITERAL_SHIFT
9187 /*-----------------------------------------------------------------*/
9188 /* genRightShiftLiteral - right shifting by known count            */
9189 /*-----------------------------------------------------------------*/
9190 static bool
9191 genRightShiftLiteral (operand * left,
9192                       operand * right,
9193                       operand * result,
9194                       iCode * ic,
9195                       int sign)
9196 {
9197   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
9198   int size;
9199
9200   size = getSize (operandType (result));
9201
9202   D(emitcode (";", "genRightShiftLiteral (%d), size %d", shCount, size););
9203
9204   /* We only handle certain easy cases so far. */
9205   if ((shCount != 0)
9206    && (shCount < (size * 8))
9207    && (size != 1)
9208    && (size != 2)
9209    && (size != 4))
9210   {
9211       D(emitcode (";", "genRightShiftLiteral wimping out"););
9212       return FALSE;
9213   }
9214
9215   freeAsmop (right, NULL, ic, TRUE);
9216
9217   aopOp (left, ic, FALSE, FALSE);
9218   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9219
9220 #if VIEW_SIZE
9221   emitcode ("; shift right ", "result %d, left %d", AOP_SIZE (result),
9222             AOP_SIZE (left));
9223 #endif
9224
9225   /* test the LEFT size !!! */
9226
9227   /* I suppose that the left size >= result size */
9228   if (shCount == 0)
9229   {
9230       size = getDataSize (result);
9231       _startLazyDPSEvaluation();
9232       while (size--)
9233       {
9234         movLeft2Result (left, size, result, size, 0);
9235       }
9236       _endLazyDPSEvaluation();
9237   }
9238   else if (shCount >= (size * 8))
9239     {
9240       if (sign)
9241       {
9242         /* get sign in acc.7 */
9243         MOVA (aopGet (AOP (left), size - 1, FALSE, FALSE, NULL));
9244       }
9245       addSign (result, LSB, sign);
9246     }
9247   else
9248     {
9249       switch (size)
9250         {
9251         case 1:
9252           genrshOne (result, left, shCount, sign);
9253           break;
9254
9255         case 2:
9256           genrshTwo (result, left, shCount, sign);
9257           break;
9258 #if 1
9259         case 4:
9260           genrshFour (result, left, shCount, sign);
9261           break;
9262 #endif
9263         default:
9264           break;
9265         }
9266     }
9267   freeAsmop (left, NULL, ic, TRUE);
9268   freeAsmop (result, NULL, ic, TRUE);
9269
9270   return TRUE;
9271 }
9272 #endif
9273
9274 /*-----------------------------------------------------------------*/
9275 /* genSignedRightShift - right shift of signed number              */
9276 /*-----------------------------------------------------------------*/
9277 static void
9278 genSignedRightShift (iCode * ic)
9279 {
9280   operand *right, *left, *result;
9281   int size, offset;
9282   char *l;
9283   symbol *tlbl, *tlbl1;
9284
9285   D (emitcode (";", "genSignedRightShift "););
9286
9287   /* we do it the hard way put the shift count in b
9288      and loop thru preserving the sign */
9289
9290   right = IC_RIGHT (ic);
9291   left = IC_LEFT (ic);
9292   result = IC_RESULT (ic);
9293
9294   aopOp (right, ic, FALSE, FALSE);
9295
9296 #ifdef BETTER_LITERAL_SHIFT
9297   if (AOP_TYPE (right) == AOP_LIT)
9298     {
9299       if (genRightShiftLiteral (left, right, result, ic, 1))
9300       {
9301         return;
9302       }
9303     }
9304 #endif
9305   /* shift count is unknown then we have to form
9306      a loop get the loop count in B : Note: we take
9307      only the lower order byte since shifting
9308      more that 32 bits make no sense anyway, ( the
9309      largest size of an object can be only 32 bits ) */
9310
9311   if (AOP_TYPE (right) == AOP_LIT)
9312   {
9313       /* Really should be handled by genRightShiftLiteral,
9314        * but since I'm too lazy to fix that today, at least we can make
9315        * some small improvement.
9316        */
9317        emitcode("mov", "b,#!constbyte",
9318                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9319   }
9320   else
9321   {
9322         MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
9323         emitcode ("inc", "b");
9324   }
9325   freeAsmop (right, NULL, ic, TRUE);
9326   aopOp (left, ic, FALSE, FALSE);
9327   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9328
9329   /* now move the left to the result if they are not the
9330      same */
9331   if (!sameRegs (AOP (left), AOP (result)) &&
9332       AOP_SIZE (result) > 1)
9333     {
9334
9335       size = AOP_SIZE (result);
9336       offset = 0;
9337       _startLazyDPSEvaluation ();
9338       while (size--)
9339         {
9340           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
9341           if (*l == '@' && IS_AOP_PREG (result))
9342             {
9343
9344               emitcode ("mov", "a,%s", l);
9345               aopPut (AOP (result), "a", offset);
9346             }
9347           else
9348             aopPut (AOP (result), l, offset);
9349           offset++;
9350         }
9351       _endLazyDPSEvaluation ();
9352     }
9353
9354   /* mov the highest order bit to OVR */
9355   tlbl = newiTempLabel (NULL);
9356   tlbl1 = newiTempLabel (NULL);
9357
9358   size = AOP_SIZE (result);
9359   offset = size - 1;
9360   MOVA (aopGet (AOP (left), offset, FALSE, FALSE, NULL));
9361   emitcode ("rlc", "a");
9362   emitcode ("mov", "ov,c");
9363   /* if it is only one byte then */
9364   if (size == 1)
9365     {
9366       MOVA( aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9367       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9368       emitcode ("", "!tlabeldef", tlbl->key + 100);
9369       emitcode ("mov", "c,ov");
9370       emitcode ("rrc", "a");
9371       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9372       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9373       aopPut (AOP (result), "a", 0);
9374       goto release;
9375     }
9376
9377   reAdjustPreg (AOP (result));
9378   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9379   emitcode ("", "!tlabeldef", tlbl->key + 100);
9380   emitcode ("mov", "c,ov");
9381   _startLazyDPSEvaluation ();
9382   while (size--)
9383     {
9384       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
9385       emitcode ("rrc", "a");
9386       aopPut (AOP (result), "a", offset--);
9387     }
9388   _endLazyDPSEvaluation ();
9389   reAdjustPreg (AOP (result));
9390   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9391   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9392
9393 release:
9394   freeAsmop (left, NULL, ic, TRUE);
9395   freeAsmop (result, NULL, ic, TRUE);
9396 }
9397
9398 /*-----------------------------------------------------------------*/
9399 /* genRightShift - generate code for right shifting                */
9400 /*-----------------------------------------------------------------*/
9401 static void
9402 genRightShift (iCode * ic)
9403 {
9404   operand *right, *left, *result;
9405   sym_link *letype;
9406   int size, offset;
9407   char *l;
9408   symbol *tlbl, *tlbl1;
9409
9410   D (emitcode (";", "genRightShift "););
9411
9412   /* if signed then we do it the hard way preserve the
9413      sign bit moving it inwards */
9414   letype = getSpec (operandType (IC_LEFT (ic)));
9415
9416   if (!SPEC_USIGN (letype))
9417     {
9418       genSignedRightShift (ic);
9419       return;
9420     }
9421
9422   /* signed & unsigned types are treated the same : i.e. the
9423      signed is NOT propagated inwards : quoting from the
9424      ANSI - standard : "for E1 >> E2, is equivalent to division
9425      by 2**E2 if unsigned or if it has a non-negative value,
9426      otherwise the result is implementation defined ", MY definition
9427      is that the sign does not get propagated */
9428
9429   right = IC_RIGHT (ic);
9430   left = IC_LEFT (ic);
9431   result = IC_RESULT (ic);
9432
9433   aopOp (right, ic, FALSE, FALSE);
9434
9435 #ifdef BETTER_LITERAL_SHIFT
9436   /* if the shift count is known then do it
9437      as efficiently as possible */
9438   if (AOP_TYPE (right) == AOP_LIT)
9439     {
9440       if (genRightShiftLiteral (left, right, result, ic, 0))
9441       {
9442         return;
9443       }
9444     }
9445 #endif
9446
9447   /* shift count is unknown then we have to form
9448      a loop get the loop count in B : Note: we take
9449      only the lower order byte since shifting
9450      more that 32 bits make no sense anyway, ( the
9451      largest size of an object can be only 32 bits ) */
9452
9453   if (AOP_TYPE (right) == AOP_LIT)
9454   {
9455       /* Really should be handled by genRightShiftLiteral,
9456        * but since I'm too lazy to fix that today, at least we can make
9457        * some small improvement.
9458        */
9459        emitcode("mov", "b,#!constbyte",
9460                 ((int) floatFromVal (AOP (right)->aopu.aop_lit)) + 1);
9461   }
9462   else
9463   {
9464       MOVB(aopGet (AOP (right), 0, FALSE, FALSE, "b"));
9465       emitcode ("inc", "b");
9466   }
9467   freeAsmop (right, NULL, ic, TRUE);
9468   aopOp (left, ic, FALSE, FALSE);
9469   aopOp (result, ic, FALSE, AOP_USESDPTR(left));
9470
9471   /* now move the left to the result if they are not the
9472      same */
9473   if (!sameRegs (AOP (left), AOP (result)) &&
9474       AOP_SIZE (result) > 1)
9475     {
9476
9477       size = AOP_SIZE (result);
9478       offset = 0;
9479       _startLazyDPSEvaluation ();
9480       while (size--)
9481         {
9482           l = aopGet (AOP (left), offset, FALSE, TRUE, NULL);
9483           if (*l == '@' && IS_AOP_PREG (result))
9484             {
9485
9486               emitcode ("mov", "a,%s", l);
9487               aopPut (AOP (result), "a", offset);
9488             }
9489           else
9490             aopPut (AOP (result), l, offset);
9491           offset++;
9492         }
9493       _endLazyDPSEvaluation ();
9494     }
9495
9496   tlbl = newiTempLabel (NULL);
9497   tlbl1 = newiTempLabel (NULL);
9498   size = AOP_SIZE (result);
9499   offset = size - 1;
9500
9501   /* if it is only one byte then */
9502   if (size == 1)
9503     {
9504       MOVA (aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9505       emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9506       emitcode ("", "!tlabeldef", tlbl->key + 100);
9507       CLRC;
9508       emitcode ("rrc", "a");
9509       emitcode ("", "!tlabeldef", tlbl1->key + 100);
9510       emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9511       aopPut (AOP (result), "a", 0);
9512       goto release;
9513     }
9514
9515   reAdjustPreg (AOP (result));
9516   emitcode ("sjmp", "!tlabel", tlbl1->key + 100);
9517   emitcode ("", "!tlabeldef", tlbl->key + 100);
9518   CLRC;
9519   _startLazyDPSEvaluation ();
9520   while (size--)
9521     {
9522       MOVA (aopGet (AOP (result), offset, FALSE, FALSE, NULL));
9523       emitcode ("rrc", "a");
9524       aopPut (AOP (result), "a", offset--);
9525     }
9526   _endLazyDPSEvaluation ();
9527   reAdjustPreg (AOP (result));
9528
9529   emitcode ("", "!tlabeldef", tlbl1->key + 100);
9530   emitcode ("djnz", "b,!tlabel", tlbl->key + 100);
9531
9532 release:
9533   freeAsmop (left, NULL, ic, TRUE);
9534   freeAsmop (result, NULL, ic, TRUE);
9535 }
9536
9537
9538 /*-----------------------------------------------------------------*/
9539 /* emitPtrByteGet - emits code to get a byte into A through a      */
9540 /*                  pointer register (R0, R1, or DPTR). The        */
9541 /*                  original value of A can be preserved in B.     */
9542 /*-----------------------------------------------------------------*/
9543 static void
9544 emitPtrByteGet (char *rname, int p_type, bool preserveAinB)
9545 {
9546   switch (p_type)
9547     {
9548     case IPOINTER:
9549     case POINTER:
9550       if (preserveAinB)
9551         emitcode ("mov", "b,a");
9552       emitcode ("mov", "a,@%s", rname);
9553       break;
9554
9555     case PPOINTER:
9556       if (preserveAinB)
9557         emitcode ("mov", "b,a");
9558       emitcode ("movx", "a,@%s", rname);
9559       break;
9560
9561     case FPOINTER:
9562       if (preserveAinB)
9563         emitcode ("mov", "b,a");
9564       emitcode ("movx", "a,@dptr");
9565       break;
9566
9567     case CPOINTER:
9568       if (preserveAinB)
9569         emitcode ("mov", "b,a");
9570       emitcode ("clr", "a");
9571       emitcode ("movc", "a,@a+dptr");
9572       break;
9573
9574     case GPOINTER:
9575       if (preserveAinB)
9576         {
9577           emitcode ("push", "b");
9578           emitcode ("push", "acc");
9579         }
9580       emitcode ("lcall", "__gptrget");
9581       if (preserveAinB)
9582         emitcode ("pop", "b");
9583       break;
9584     }
9585 }
9586
9587 /*-----------------------------------------------------------------*/
9588 /* emitPtrByteSet - emits code to set a byte from src through a    */
9589 /*                  pointer register (R0, R1, or DPTR).            */
9590 /*-----------------------------------------------------------------*/
9591 static void
9592 emitPtrByteSet (char *rname, int p_type, char *src)
9593 {
9594   switch (p_type)
9595     {
9596     case IPOINTER:
9597     case POINTER:
9598       if (*src=='@')
9599         {
9600           MOVA (src);
9601           emitcode ("mov", "@%s,a", rname);
9602         }
9603       else
9604         emitcode ("mov", "@%s,%s", rname, src);
9605       break;
9606
9607     case PPOINTER:
9608       MOVA (src);
9609       emitcode ("movx", "@%s,a", rname);
9610       break;
9611
9612     case FPOINTER:
9613       MOVA (src);
9614       emitcode ("movx", "@dptr,a");
9615       break;
9616
9617     case GPOINTER:
9618       MOVA (src);
9619       emitcode ("lcall", "__gptrput");
9620       break;
9621     }
9622 }
9623
9624 /*-----------------------------------------------------------------*/
9625 /* genUnpackBits - generates code for unpacking bits               */
9626 /*-----------------------------------------------------------------*/
9627 static void
9628 genUnpackBits (operand * result, char *rname, int ptype)
9629 {
9630   int offset = 0;       /* result byte offset */
9631   int rsize;            /* result size */
9632   int rlen = 0;         /* remaining bitfield length */
9633   sym_link *etype;      /* bitfield type information */
9634   int blen;             /* bitfield length */
9635   int bstr;             /* bitfield starting bit within byte */
9636
9637   D(emitcode (";     genUnpackBits",""));
9638
9639   etype = getSpec (operandType (result));
9640   rsize = getSize (operandType (result));
9641   blen = SPEC_BLEN (etype);
9642   bstr = SPEC_BSTR (etype);
9643
9644   /* If the bitfield length is less than a byte */
9645   if (blen < 8)
9646     {
9647       emitPtrByteGet (rname, ptype, FALSE);
9648       AccRsh (bstr);
9649       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8 - blen));
9650       aopPut (AOP (result), "a", offset++);
9651       goto finish;
9652     }
9653
9654   /* Bit field did not fit in a byte. Copy all
9655      but the partial byte at the end.  */
9656   for (rlen=blen;rlen>=8;rlen-=8)
9657     {
9658       emitPtrByteGet (rname, ptype, FALSE);
9659       aopPut (AOP (result), "a", offset++);
9660       if (rlen>8)
9661         emitcode ("inc", "%s", rname);
9662     }
9663
9664   /* Handle the partial byte at the end */
9665   if (rlen)
9666     {
9667       emitPtrByteGet (rname, ptype, FALSE);
9668       emitcode ("anl", "a,#!constbyte", ((unsigned char) -1) >> (8-rlen));
9669       aopPut (AOP (result), "a", offset++);
9670     }
9671
9672 finish:
9673   if (offset < rsize)
9674     {
9675       rsize -= offset;
9676       while (rsize--)
9677         aopPut (AOP (result), zero, offset++);
9678     }
9679 }
9680
9681
9682 /*-----------------------------------------------------------------*/
9683 /* genDataPointerGet - generates code when ptr offset is known     */
9684 /*-----------------------------------------------------------------*/
9685 static void
9686 genDataPointerGet (operand * left,
9687                    operand * result,
9688                    iCode * ic)
9689 {
9690   char *l;
9691   char buff[256];
9692   int size, offset = 0;
9693   aopOp (result, ic, TRUE, FALSE);
9694
9695   /* get the string representation of the name */
9696   l = aopGet (AOP (left), 0, FALSE, TRUE, NULL);
9697   size = AOP_SIZE (result);
9698   _startLazyDPSEvaluation ();
9699   while (size--)
9700     {
9701         if (offset)
9702         {
9703             SNPRINTF (buff, sizeof(buff),
9704                       "(%s + %d)", l + 1, offset);
9705         }
9706         else
9707         {
9708             SNPRINTF (buff, sizeof(buff),
9709                       "%s", l + 1);
9710         }
9711       aopPut (AOP (result), buff, offset++);
9712     }
9713   _endLazyDPSEvaluation ();
9714
9715   freeAsmop (left, NULL, ic, TRUE);
9716   freeAsmop (result, NULL, ic, TRUE);
9717 }
9718
9719 /*-----------------------------------------------------------------*/
9720 /* genNearPointerGet - emitcode for near pointer fetch             */
9721 /*-----------------------------------------------------------------*/
9722 static void
9723 genNearPointerGet (operand * left,
9724                    operand * result,
9725                    iCode * ic,
9726                    iCode *pi)
9727 {
9728   asmop *aop = NULL;
9729   regs *preg;
9730   char *rname;
9731   sym_link *rtype, *retype, *letype;
9732   sym_link *ltype = operandType (left);
9733   char buff[80];
9734
9735   rtype = operandType (result);
9736   retype = getSpec (rtype);
9737   letype = getSpec (ltype);
9738
9739   aopOp (left, ic, FALSE, FALSE);
9740
9741   /* if left is rematerialisable and
9742      result is not bitfield variable type and
9743      the left is pointer to data space i.e
9744      lower 128 bytes of space */
9745   if (AOP_TYPE (left) == AOP_IMMD &&
9746       !IS_BITFIELD (retype) &&
9747       !IS_BITFIELD (letype) &&
9748       DCL_TYPE (ltype) == POINTER)
9749     {
9750       genDataPointerGet (left, result, ic);
9751       return;
9752     }
9753
9754   /* if the value is already in a pointer register
9755      then don't need anything more */
9756   if (!AOP_INPREG (AOP (left)))
9757     {
9758       /* otherwise get a free pointer register */
9759       aop = newAsmop (0);
9760       preg = getFreePtr (ic, &aop, FALSE);
9761       emitcode ("mov", "%s,%s",
9762                 preg->name,
9763                 aopGet (AOP (left), 0, FALSE, TRUE, DP2_RESULT_REG));
9764       rname = preg->name;
9765     }
9766   else
9767     rname = aopGet (AOP (left), 0, FALSE, FALSE, DP2_RESULT_REG);
9768
9769   freeAsmop (left, NULL, ic, TRUE);
9770   aopOp (result, ic, FALSE, FALSE);
9771
9772   /* if bitfield then unpack the bits */
9773   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9774     genUnpackBits (result, rname, POINTER);
9775   else
9776     {
9777       /* we have can just get the values */
9778       int size = AOP_SIZE (result);
9779       int offset = 0;
9780
9781       while (size--)
9782         {
9783           if (IS_AOP_PREG (result) || AOP_TYPE (result) == AOP_STK)
9784             {
9785
9786               emitcode ("mov", "a,@%s", rname);
9787               aopPut (AOP (result), "a", offset);
9788             }
9789           else
9790             {
9791               SNPRINTF (buff, sizeof(buff), "@%s", rname);
9792               aopPut (AOP (result), buff, offset);
9793             }
9794           offset++;
9795           if (size || pi)
9796             {
9797                 emitcode ("inc", "%s", rname);
9798             }
9799         }
9800     }
9801
9802   /* now some housekeeping stuff */
9803   if (aop)
9804     {
9805       /* we had to allocate for this iCode */
9806       if (pi) { /* post increment present */
9807         aopPut(AOP ( left ),rname,0);
9808       }
9809       freeAsmop (NULL, aop, ic, TRUE);
9810     }
9811   else
9812     {
9813       /* we did not allocate which means left
9814          already in a pointer register, then
9815          if size > 0 && this could be used again
9816          we have to point it back to where it
9817          belongs */
9818       if (AOP_SIZE (result) > 1 &&
9819           !OP_SYMBOL (left)->remat &&
9820           (OP_SYMBOL (left)->liveTo > ic->seq ||
9821            ic->depth) &&
9822           !pi)
9823         {
9824           int size = AOP_SIZE (result) - 1;
9825           while (size--)
9826             emitcode ("dec", "%s", rname);
9827         }
9828     }
9829
9830   /* done */
9831   freeAsmop (result, NULL, ic, TRUE);
9832   if (pi) pi->generated = 1;
9833 }
9834
9835 /*-----------------------------------------------------------------*/
9836 /* genPagedPointerGet - emitcode for paged pointer fetch           */
9837 /*-----------------------------------------------------------------*/
9838 static void
9839 genPagedPointerGet (operand * left,
9840                     operand * result,
9841                     iCode * ic,
9842                     iCode * pi)
9843 {
9844   asmop *aop = NULL;
9845   regs *preg;
9846   char *rname;
9847   sym_link *rtype, *retype, *letype;
9848
9849   rtype = operandType (result);
9850   retype = getSpec (rtype);
9851   letype = getSpec (operandType (left));
9852   aopOp (left, ic, FALSE, FALSE);
9853
9854   /* if the value is already in a pointer register
9855      then don't need anything more */
9856   if (!AOP_INPREG (AOP (left)))
9857     {
9858       /* otherwise get a free pointer register */
9859       aop = newAsmop (0);
9860       preg = getFreePtr (ic, &aop, FALSE);
9861       emitcode ("mov", "%s,%s",
9862                 preg->name,
9863                 aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9864       rname = preg->name;
9865     }
9866   else
9867     rname = aopGet (AOP (left), 0, FALSE, FALSE, NULL);
9868
9869   freeAsmop (left, NULL, ic, TRUE);
9870   aopOp (result, ic, FALSE, FALSE);
9871
9872   /* if bitfield then unpack the bits */
9873   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
9874     genUnpackBits (result, rname, PPOINTER);
9875   else
9876     {
9877       /* we have can just get the values */
9878       int size = AOP_SIZE (result);
9879       int offset = 0;
9880
9881       while (size--)
9882         {
9883
9884           emitcode ("movx", "a,@%s", rname);
9885           aopPut (AOP (result), "a", offset);
9886
9887           offset++;
9888
9889           if (size || pi)
9890             emitcode ("inc", "%s", rname);
9891         }
9892     }
9893
9894   /* now some housekeeping stuff */
9895   if (aop)
9896     {
9897       /* we had to allocate for this iCode */
9898       if (pi) aopPut ( AOP (left), rname, 0);
9899       freeAsmop (NULL, aop, ic, TRUE);
9900     }
9901   else
9902     {
9903       /* we did not allocate which means left
9904          already in a pointer register, then
9905          if size > 0 && this could be used again
9906          we have to point it back to where it
9907          belongs */
9908       if (AOP_SIZE (result) > 1 &&
9909           !OP_SYMBOL (left)->remat &&
9910           (OP_SYMBOL (left)->liveTo > ic->seq ||
9911            ic->depth) &&
9912           !pi)
9913         {
9914           int size = AOP_SIZE (result) - 1;
9915           while (size--)
9916             emitcode ("dec", "%s", rname);
9917         }
9918     }
9919
9920   /* done */
9921   freeAsmop (result, NULL, ic, TRUE);
9922   if (pi) pi->generated = 1;
9923 }
9924
9925 /*-----------------------------------------------------------------*/
9926 /* genFarPointerGet - gget value from far space                    */
9927 /*-----------------------------------------------------------------*/
9928 static void
9929 genFarPointerGet (operand * left,
9930                   operand * result, iCode * ic, iCode *pi)
9931 {
9932     int size, offset, dopi=1;
9933   sym_link *retype = getSpec (operandType (result));
9934   sym_link *letype = getSpec (operandType (left));
9935   D (emitcode (";", "genFarPointerGet"););
9936
9937   aopOp (left, ic, FALSE, FALSE);
9938
9939   /* if the operand is already in dptr
9940      then we do nothing else we move the value to dptr */
9941   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left) )
9942     {
9943       /* if this is remateriazable */
9944       if (AOP_TYPE (left) == AOP_IMMD)
9945         {
9946           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
9947         }
9948       else
9949         {
9950           /* we need to get it byte by byte */
9951           _startLazyDPSEvaluation ();
9952           if (AOP_TYPE (left) != AOP_DPTR)
9953             {
9954               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
9955               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
9956               if (options.model == MODEL_FLAT24)
9957                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9958             }
9959           else
9960             {
9961               /* We need to generate a load to DPTR indirect through DPTR. */
9962               D (emitcode (";", "genFarPointerGet -- indirection special case."););
9963               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
9964               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
9965               if (options.model == MODEL_FLAT24)
9966                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
9967               emitcode ("pop", "dph");
9968               emitcode ("pop", "dpl");
9969               dopi =0;
9970             }
9971           _endLazyDPSEvaluation ();
9972         }
9973     }
9974   /* so dptr know contains the address */
9975   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
9976
9977   /* if bit then unpack */
9978   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
9979       if (AOP_INDPTRn(left)) {
9980           genSetDPTR(AOP(left)->aopu.dptr);
9981       }
9982       genUnpackBits (result, "dptr", FPOINTER);
9983       if (AOP_INDPTRn(left)) {
9984           genSetDPTR(0);
9985       }
9986   } else
9987     {
9988       size = AOP_SIZE (result);
9989       offset = 0;
9990
9991       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
9992           while (size--) {
9993               genSetDPTR(AOP(left)->aopu.dptr);
9994               emitcode ("movx", "a,@dptr");
9995               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
9996                   emitcode ("inc", "dptr");
9997               genSetDPTR (0);
9998               aopPut (AOP (result), "a", offset++);
9999           }
10000       } else {
10001           _startLazyDPSEvaluation ();
10002           while (size--) {
10003               if (AOP_INDPTRn(left)) {
10004                   genSetDPTR(AOP(left)->aopu.dptr);
10005               } else {
10006                   genSetDPTR (0);
10007               }
10008               _flushLazyDPS ();
10009
10010               emitcode ("movx", "a,@dptr");
10011               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10012                   emitcode ("inc", "dptr");
10013
10014               aopPut (AOP (result), "a", offset++);
10015           }
10016           _endLazyDPSEvaluation ();
10017       }
10018     }
10019   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10020       if (!AOP_INDPTRn(left)) {
10021           _startLazyDPSEvaluation ();
10022           aopPut ( AOP (left), "dpl", 0);
10023           aopPut ( AOP (left), "dph", 1);
10024           if (options.model == MODEL_FLAT24)
10025               aopPut ( AOP (left), "dpx", 2);
10026           _endLazyDPSEvaluation ();
10027       }
10028     pi->generated = 1;
10029   } else if ((AOP_IS_STR(left) || AOP_INDPTRn(left)) &&
10030              AOP_SIZE(result) > 1 &&
10031              IS_SYMOP(left) &&
10032              (OP_SYMBOL(left)->liveTo > ic->seq || ic->depth)) {
10033
10034       size = AOP_SIZE (result) - 1;
10035       if (AOP_INDPTRn(left)) {
10036           genSetDPTR(AOP(left)->aopu.dptr);
10037       }
10038       while (size--) emitcode ("lcall","__decdptr");
10039       if (AOP_INDPTRn(left)) {
10040           genSetDPTR(0);
10041       }
10042   }
10043
10044   freeAsmop (left, NULL, ic, TRUE);
10045   freeAsmop (result, NULL, ic, TRUE);
10046 }
10047
10048 /*-----------------------------------------------------------------*/
10049 /* genCodePointerGet - get value from code space                  */
10050 /*-----------------------------------------------------------------*/
10051 static void
10052 genCodePointerGet (operand * left,
10053                     operand * result, iCode * ic, iCode *pi)
10054 {
10055   int size, offset, dopi=1;
10056   sym_link *retype = getSpec (operandType (result));
10057
10058   aopOp (left, ic, FALSE, FALSE);
10059
10060   /* if the operand is already in dptr
10061      then we do nothing else we move the value to dptr */
10062   if (AOP_TYPE (left) != AOP_STR && !AOP_INDPTRn(left))
10063     {
10064       /* if this is remateriazable */
10065       if (AOP_TYPE (left) == AOP_IMMD)
10066         {
10067           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
10068         }
10069       else
10070         {                       /* we need to get it byte by byte */
10071           _startLazyDPSEvaluation ();
10072           if (AOP_TYPE (left) != AOP_DPTR)
10073             {
10074               emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
10075               emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
10076               if (options.model == MODEL_FLAT24)
10077                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
10078             }
10079           else
10080             {
10081               /* We need to generate a load to DPTR indirect through DPTR. */
10082               D (emitcode (";", "gencodePointerGet -- indirection special case."););
10083               emitcode ("push", "%s", aopGet (AOP (left), 0, FALSE, TRUE, NULL));
10084               emitcode ("push", "%s", aopGet (AOP (left), 1, FALSE, TRUE, NULL));
10085               if (options.model == MODEL_FLAT24)
10086                 emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
10087               emitcode ("pop", "dph");
10088               emitcode ("pop", "dpl");
10089               dopi=0;
10090             }
10091           _endLazyDPSEvaluation ();
10092         }
10093     }
10094   /* so dptr know contains the address */
10095   aopOp (result, ic, FALSE, (AOP_INDPTRn(left) ? FALSE : TRUE));
10096
10097   /* if bit then unpack */
10098   if (IS_BITFIELD (retype)) {
10099       if (AOP_INDPTRn(left)) {
10100           genSetDPTR(AOP(left)->aopu.dptr);
10101       }
10102       genUnpackBits (result, "dptr", CPOINTER);
10103       if (AOP_INDPTRn(left)) {
10104           genSetDPTR(0);
10105       }
10106   } else
10107     {
10108       size = AOP_SIZE (result);
10109       offset = 0;
10110       if (AOP_INDPTRn(left) && AOP_USESDPTR(result)) {
10111           while (size--) {
10112               genSetDPTR(AOP(left)->aopu.dptr);
10113               emitcode ("clr", "a");
10114               emitcode ("movc", "a,@a+dptr");
10115               if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10116                   emitcode ("inc", "dptr");
10117               genSetDPTR (0);
10118               aopPut (AOP (result), "a", offset++);
10119           }
10120       } else {
10121           _startLazyDPSEvaluation ();
10122           while (size--)
10123               {
10124                   if (AOP_INDPTRn(left)) {
10125                       genSetDPTR(AOP(left)->aopu.dptr);
10126                   } else {
10127                       genSetDPTR (0);
10128                   }
10129                   _flushLazyDPS ();
10130
10131                   emitcode ("clr", "a");
10132                   emitcode ("movc", "a,@a+dptr");
10133                   if (size || (dopi && pi && AOP_TYPE (left) != AOP_IMMD))
10134                       emitcode ("inc", "dptr");
10135                   aopPut (AOP (result), "a", offset++);
10136               }
10137           _endLazyDPSEvaluation ();
10138       }
10139     }
10140   if (dopi && pi && AOP_TYPE (left) != AOP_IMMD) {
10141       if (!AOP_INDPTRn(left)) {
10142           _startLazyDPSEvaluation ();
10143
10144           aopPut ( AOP (left), "dpl", 0);
10145           aopPut ( AOP (left), "dph", 1);
10146           if (options.model == MODEL_FLAT24)
10147               aopPut ( AOP (left), "dpx", 2);
10148
10149           _endLazyDPSEvaluation ();
10150       }
10151       pi->generated = 1;
10152   } else if ((OP_SYMBOL(left)->ruonly || AOP_INDPTRn(left)) &&
10153              AOP_SIZE(result) > 1 &&
10154              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10155
10156       size = AOP_SIZE (result) - 1;
10157       if (AOP_INDPTRn(left)) {
10158           genSetDPTR(AOP(left)->aopu.dptr);
10159       }
10160       while (size--) emitcode ("lcall","__decdptr");
10161       if (AOP_INDPTRn(left)) {
10162           genSetDPTR(0);
10163       }
10164   }
10165
10166   freeAsmop (left, NULL, ic, TRUE);
10167   freeAsmop (result, NULL, ic, TRUE);
10168 }
10169
10170 /*-----------------------------------------------------------------*/
10171 /* genGenPointerGet - gget value from generic pointer space        */
10172 /*-----------------------------------------------------------------*/
10173 static void
10174 genGenPointerGet (operand * left,
10175                   operand * result, iCode * ic, iCode * pi)
10176 {
10177   int size, offset;
10178   sym_link *retype = getSpec (operandType (result));
10179   sym_link *letype = getSpec (operandType (left));
10180
10181   D (emitcode (";", "genGenPointerGet "); );
10182
10183   aopOp (left, ic, FALSE, (AOP_IS_STR(left) ? FALSE : TRUE));
10184
10185   /* if the operand is already in dptr
10186      then we do nothing else we move the value to dptr */
10187   if (AOP_TYPE (left) != AOP_STR)
10188     {
10189       /* if this is rematerializable */
10190       if (AOP_TYPE (left) == AOP_IMMD)
10191         {
10192           emitcode ("mov", "dptr,%s", aopGet (AOP (left), 0, TRUE, FALSE, NULL));
10193           if (AOP(left)->aopu.aop_immd.from_cast_remat)
10194             {
10195               MOVB(aopGet(AOP (left), AOP_SIZE(left)-1, FALSE, FALSE, NULL));
10196             }
10197           else
10198             {
10199               emitcode ("mov", "b,#%d", pointerCode (retype));
10200             }
10201         }
10202       else
10203         {                       /* we need to get it byte by byte */
10204           _startLazyDPSEvaluation ();
10205           emitcode ("mov", "dpl,%s", aopGet (AOP(left),0,FALSE,FALSE,NULL));
10206           emitcode ("mov", "dph,%s", aopGet (AOP(left),1,FALSE,FALSE,NULL));
10207           if (options.model == MODEL_FLAT24) {
10208               emitcode ("mov", "dpx,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
10209               emitcode ("mov", "b,%s", aopGet (AOP(left),3,FALSE,FALSE,NULL));
10210           } else {
10211               emitcode ("mov", "b,%s", aopGet (AOP(left),2,FALSE,FALSE,NULL));
10212           }
10213           _endLazyDPSEvaluation ();
10214         }
10215     }
10216
10217   /* so dptr-b now contains the address */
10218   _G.bInUse++;
10219   aopOp (result, ic, FALSE, TRUE);
10220   _G.bInUse--;
10221
10222   /* if bit then unpack */
10223   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10224   {
10225     genUnpackBits (result, "dptr", GPOINTER);
10226   }
10227   else
10228     {
10229         size = AOP_SIZE (result);
10230         offset = 0;
10231
10232         while (size--)
10233         {
10234             if (size)
10235             {
10236                 // Get two bytes at a time, results in _AP & A.
10237                 // dptr will be incremented ONCE by __gptrgetWord.
10238                 //
10239                 // Note: any change here must be coordinated
10240                 // with the implementation of __gptrgetWord
10241                 // in device/lib/_gptrget.c
10242                 emitcode ("lcall", "__gptrgetWord");
10243                 aopPut (AOP (result), DP2_RESULT_REG, offset++);
10244                 aopPut (AOP (result), "a", offset++);
10245                 size--;
10246             }
10247             else
10248             {
10249                 // Only one byte to get.
10250                 emitcode ("lcall", "__gptrget");
10251                 aopPut (AOP (result), "a", offset++);
10252             }
10253
10254             if (size || (pi && AOP_TYPE (left) != AOP_IMMD))
10255             {
10256                 emitcode ("inc", "dptr");
10257             }
10258         }
10259     }
10260
10261   if (pi && AOP_TYPE (left) != AOP_IMMD) {
10262     _startLazyDPSEvaluation ();
10263
10264     aopPut ( AOP (left), "dpl", 0);
10265     aopPut ( AOP (left), "dph", 1);
10266     if (options.model == MODEL_FLAT24) {
10267         aopPut ( AOP (left), "dpx", 2);
10268         aopPut ( AOP (left), "b", 3);
10269     } else  aopPut ( AOP (left), "b", 2);
10270
10271     _endLazyDPSEvaluation ();
10272
10273     pi->generated = 1;
10274   } else if (OP_SYMBOL(left)->ruonly && AOP_SIZE(result) > 1 &&
10275              (OP_SYMBOL (left)->liveTo > ic->seq || ic->depth)) {
10276
10277       size = AOP_SIZE (result) - 1;
10278       while (size--) emitcode ("lcall","__decdptr");
10279   }
10280
10281   freeAsmop (left, NULL, ic, TRUE);
10282   freeAsmop (result, NULL, ic, TRUE);
10283 }
10284
10285 /*-----------------------------------------------------------------*/
10286 /* genPointerGet - generate code for pointer get                   */
10287 /*-----------------------------------------------------------------*/
10288 static void
10289 genPointerGet (iCode * ic, iCode *pi)
10290 {
10291   operand *left, *result;
10292   sym_link *type, *etype;
10293   int p_type;
10294
10295   D (emitcode (";", "genPointerGet ");
10296     );
10297
10298   left = IC_LEFT (ic);
10299   result = IC_RESULT (ic);
10300
10301   /* depending on the type of pointer we need to
10302      move it to the correct pointer register */
10303   type = operandType (left);
10304   etype = getSpec (type);
10305   /* if left is of type of pointer then it is simple */
10306   if (IS_PTR (type) && !IS_FUNC (type->next))
10307     p_type = DCL_TYPE (type);
10308   else
10309     {
10310       /* we have to go by the storage class */
10311       p_type = PTR_TYPE (SPEC_OCLS (etype));
10312     }
10313   /* special case when cast remat */
10314   if (p_type == GPOINTER && OP_SYMBOL(left)->remat &&
10315       IS_CAST_ICODE(OP_SYMBOL(left)->rematiCode))
10316     {
10317       left = IC_RIGHT(OP_SYMBOL(left)->rematiCode);
10318       type = operandType (left);
10319       p_type = DCL_TYPE (type);
10320     }
10321   /* now that we have the pointer type we assign
10322      the pointer values */
10323   switch (p_type)
10324     {
10325
10326     case POINTER:
10327     case IPOINTER:
10328       genNearPointerGet (left, result, ic, pi);
10329       break;
10330
10331     case PPOINTER:
10332       genPagedPointerGet (left, result, ic, pi);
10333       break;
10334
10335     case FPOINTER:
10336       genFarPointerGet (left, result, ic, pi);
10337       break;
10338
10339     case CPOINTER:
10340       genCodePointerGet (left, result, ic, pi);
10341       break;
10342
10343     case GPOINTER:
10344       genGenPointerGet (left, result, ic, pi);
10345       break;
10346     }
10347
10348 }
10349
10350 /*-----------------------------------------------------------------*/
10351 /* genPackBits - generates code for packed bit storage             */
10352 /*-----------------------------------------------------------------*/
10353 static void
10354 genPackBits (sym_link * etype,
10355              operand * right,
10356              char *rname, int p_type)
10357 {
10358   int offset = 0;       /* source byte offset */
10359   int rlen = 0;         /* remaining bitfield length */
10360   int blen;             /* bitfield length */
10361   int bstr;             /* bitfield starting bit within byte */
10362   int litval;           /* source literal value (if AOP_LIT) */
10363   unsigned char mask;   /* bitmask within current byte */
10364
10365   D(emitcode (";     genPackBits",""));
10366
10367   blen = SPEC_BLEN (etype);
10368   bstr = SPEC_BSTR (etype);
10369
10370   /* If the bitfield length is less than a byte */
10371   if (blen < 8)
10372     {
10373       mask = ((unsigned char) (0xFF << (blen + bstr)) |
10374               (unsigned char) (0xFF >> (8 - bstr)));
10375
10376       if (AOP_TYPE (right) == AOP_LIT)
10377         {
10378           /* Case with a bitfield length <8 and literal source
10379           */
10380           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10381           litval <<= bstr;
10382           litval &= (~mask) & 0xff;
10383           emitPtrByteGet (rname, p_type, FALSE);
10384           if ((mask|litval)!=0xff)
10385             emitcode ("anl","a,#!constbyte", mask);
10386           if (litval)
10387             emitcode ("orl","a,#!constbyte", litval);
10388         }
10389       else
10390         {
10391           if ((blen==1) && (p_type!=GPOINTER))
10392             {
10393               /* Case with a bitfield length == 1 and no generic pointer
10394               */
10395               if (AOP_TYPE (right) == AOP_CRY)
10396                 emitcode ("mov", "c,%s", AOP(right)->aopu.aop_dir);
10397               else
10398                 {
10399                   MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
10400                   emitcode ("rrc","a");
10401                 }
10402               emitPtrByteGet (rname, p_type, FALSE);
10403               emitcode ("mov","acc.%d,c",bstr);
10404             }
10405           else
10406             {
10407               /* Case with a bitfield length < 8 and arbitrary source
10408               */
10409               MOVA (aopGet (AOP (right), 0, FALSE, FALSE, NULL));
10410               /* shift and mask source value */
10411               AccLsh (bstr);
10412               emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
10413
10414               /* transfer A to B and get next byte */
10415               emitPtrByteGet (rname, p_type, TRUE);
10416
10417               emitcode ("anl", "a,#!constbyte", mask);
10418               emitcode ("orl", "a,b");
10419               if (p_type == GPOINTER)
10420                 emitcode ("pop", "b");
10421            }
10422         }
10423
10424       emitPtrByteSet (rname, p_type, "a");
10425       return;
10426     }
10427
10428   /* Bit length is greater than 7 bits. In this case, copy  */
10429   /* all except the partial byte at the end                 */
10430   for (rlen=blen;rlen>=8;rlen-=8)
10431     {
10432       emitPtrByteSet (rname, p_type,
10433                       aopGet (AOP (right), offset++, FALSE, TRUE, NULL) );
10434       if (rlen>8)
10435         emitcode ("inc", "%s", rname);
10436     }
10437
10438   /* If there was a partial byte at the end */
10439   if (rlen)
10440     {
10441       mask = (((unsigned char) -1 << rlen) & 0xff);
10442
10443       if (AOP_TYPE (right) == AOP_LIT)
10444         {
10445           /* Case with partial byte and literal source
10446           */
10447           litval = (int) floatFromVal (AOP (right)->aopu.aop_lit);
10448           litval >>= (blen-rlen);
10449           litval &= (~mask) & 0xff;
10450           emitPtrByteGet (rname, p_type, FALSE);
10451           if ((mask|litval)!=0xff)
10452             emitcode ("anl","a,#!constbyte", mask);
10453           if (litval)
10454             emitcode ("orl","a,#!constbyte", litval);
10455         }
10456       else
10457         {
10458           /* Case with partial byte and arbitrary source
10459           */
10460           MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10461           emitcode ("anl", "a,#!constbyte", (~mask) & 0xff);
10462
10463           /* transfer A to B and get next byte */
10464           emitPtrByteGet (rname, p_type, TRUE);
10465
10466           emitcode ("anl", "a,#!constbyte", mask);
10467           emitcode ("orl", "a,b");
10468           if (p_type == GPOINTER)
10469             emitcode ("pop", "b");
10470         }
10471       emitPtrByteSet (rname, p_type, "a");
10472     }
10473
10474 }
10475
10476
10477 /*-----------------------------------------------------------------*/
10478 /* genDataPointerSet - remat pointer to data space                 */
10479 /*-----------------------------------------------------------------*/
10480 static void
10481 genDataPointerSet (operand * right,
10482                    operand * result,
10483                    iCode * ic)
10484 {
10485   int size, offset = 0;
10486   char *l, buff[256];
10487
10488   aopOp (right, ic, FALSE, FALSE);
10489
10490   l = aopGet (AOP (result), 0, FALSE, TRUE, NULL);
10491   size = AOP_SIZE (right);
10492   while (size--)
10493     {
10494       if (offset)
10495         {
10496             SNPRINTF (buff, sizeof(buff), "(%s + %d)", l + 1, offset);
10497         }
10498       else
10499         {
10500             SNPRINTF (buff, sizeof(buff), "%s", l + 1);
10501         }
10502
10503       emitcode ("mov", "%s,%s", buff,
10504                 aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10505     }
10506
10507   freeAsmop (right, NULL, ic, TRUE);
10508   freeAsmop (result, NULL, ic, TRUE);
10509 }
10510
10511 /*-----------------------------------------------------------------*/
10512 /* genNearPointerSet - emitcode for near pointer put                */
10513 /*-----------------------------------------------------------------*/
10514 static void
10515 genNearPointerSet (operand * right,
10516                    operand * result,
10517                    iCode * ic,
10518                    iCode * pi)
10519 {
10520   asmop *aop = NULL;
10521   char *rname, *l;
10522   sym_link *retype, *letype;
10523   sym_link *ptype = operandType (result);
10524
10525   retype = getSpec (operandType (right));
10526   letype = getSpec (ptype);
10527
10528   aopOp (result, ic, FALSE, FALSE);
10529
10530   /* if the result is rematerializable &
10531      in data space & not a bit variable */
10532   if (AOP_TYPE (result) == AOP_IMMD &&
10533       DCL_TYPE (ptype) == POINTER &&
10534       !IS_BITVAR (retype) &&
10535       !IS_BITVAR (letype))
10536     {
10537       genDataPointerSet (right, result, ic);
10538       return;
10539     }
10540
10541   /* if the value is already in a pointer register
10542      then don't need anything more */
10543   if (!AOP_INPREG (AOP (result)))
10544     {
10545       /* otherwise get a free pointer register */
10546       regs *preg;
10547
10548       aop = newAsmop (0);
10549       preg = getFreePtr (ic, &aop, FALSE);
10550       emitcode ("mov", "%s,%s",
10551                 preg->name,
10552                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10553       rname = preg->name;
10554     }
10555   else
10556     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
10557
10558   aopOp (right, ic, FALSE, FALSE);
10559
10560   /* if bitfield then unpack the bits */
10561   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10562     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, POINTER);
10563   else
10564     {
10565       /* we have can just get the values */
10566       int size = AOP_SIZE (right);
10567       int offset = 0;
10568
10569       while (size--)
10570         {
10571           l = aopGet (AOP (right), offset, FALSE, TRUE, NULL);
10572           if (*l == '@')
10573             {
10574               MOVA (l);
10575               emitcode ("mov", "@%s,a", rname);
10576             }
10577           else
10578             emitcode ("mov", "@%s,%s", rname, l);
10579           if (size || pi)
10580             emitcode ("inc", "%s", rname);
10581           offset++;
10582         }
10583     }
10584
10585   /* now some housekeeping stuff */
10586   if (aop)
10587     {
10588       /* we had to allocate for this iCode */
10589       if (pi) aopPut (AOP (result),rname,0);
10590       freeAsmop (NULL, aop, ic, TRUE);
10591     }
10592   else
10593     {
10594       /* we did not allocate which means left
10595          already in a pointer register, then
10596          if size > 0 && this could be used again
10597          we have to point it back to where it
10598          belongs */
10599       if (AOP_SIZE (right) > 1 &&
10600           !OP_SYMBOL (result)->remat &&
10601           (OP_SYMBOL (result)->liveTo > ic->seq ||
10602            ic->depth) &&
10603           !pi)
10604         {
10605           int size = AOP_SIZE (right) - 1;
10606           while (size--)
10607             emitcode ("dec", "%s", rname);
10608         }
10609     }
10610
10611   /* done */
10612   if (pi) pi->generated = 1;
10613   freeAsmop (result, NULL, ic, TRUE);
10614   freeAsmop (right, NULL, ic, TRUE);
10615
10616
10617 }
10618
10619 /*-----------------------------------------------------------------*/
10620 /* genPagedPointerSet - emitcode for Paged pointer put             */
10621 /*-----------------------------------------------------------------*/
10622 static void
10623 genPagedPointerSet (operand * right,
10624                     operand * result,
10625                     iCode * ic,
10626                     iCode *pi)
10627 {
10628   asmop *aop = NULL;
10629   char *rname;
10630   sym_link *retype, *letype;
10631
10632   retype = getSpec (operandType (right));
10633   letype = getSpec (operandType (result));
10634
10635   aopOp (result, ic, FALSE, FALSE);
10636
10637   /* if the value is already in a pointer register
10638      then don't need anything more */
10639   if (!AOP_INPREG (AOP (result)))
10640     {
10641       /* otherwise get a free pointer register */
10642       regs *preg;
10643
10644       aop = newAsmop (0);
10645       preg = getFreePtr (ic, &aop, FALSE);
10646       emitcode ("mov", "%s,%s",
10647                 preg->name,
10648                 aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10649       rname = preg->name;
10650     }
10651   else
10652     rname = aopGet (AOP (result), 0, FALSE, FALSE, NULL);
10653
10654   aopOp (right, ic, FALSE, FALSE);
10655
10656   /* if bitfield then unpack the bits */
10657   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10658     genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, rname, PPOINTER);
10659   else
10660     {
10661       /* we have can just get the values */
10662       int size = AOP_SIZE (right);
10663       int offset = 0;
10664
10665       while (size--)
10666         {
10667           MOVA (aopGet (AOP (right), offset, FALSE, TRUE, NULL));
10668
10669           emitcode ("movx", "@%s,a", rname);
10670
10671           if (size || pi)
10672             emitcode ("inc", "%s", rname);
10673
10674           offset++;
10675         }
10676     }
10677
10678   /* now some housekeeping stuff */
10679   if (aop)
10680     {
10681       if (pi) aopPut (AOP (result),rname,0);
10682       /* we had to allocate for this iCode */
10683       freeAsmop (NULL, aop, ic, TRUE);
10684     }
10685   else
10686     {
10687       /* we did not allocate which means left
10688          already in a pointer register, then
10689          if size > 0 && this could be used again
10690          we have to point it back to where it
10691          belongs */
10692       if (AOP_SIZE (right) > 1 &&
10693           !OP_SYMBOL (result)->remat &&
10694           (OP_SYMBOL (result)->liveTo > ic->seq ||
10695            ic->depth) &&
10696           !pi)
10697         {
10698           int size = AOP_SIZE (right) - 1;
10699           while (size--)
10700             emitcode ("dec", "%s", rname);
10701         }
10702     }
10703
10704   /* done */
10705   if (pi) pi->generated = 1;
10706   freeAsmop (result, NULL, ic, TRUE);
10707   freeAsmop (right, NULL, ic, TRUE);
10708
10709
10710 }
10711
10712 /*-----------------------------------------------------------------*/
10713 /* genFarPointerSet - set value from far space                     */
10714 /*-----------------------------------------------------------------*/
10715 static void
10716 genFarPointerSet (operand * right,
10717                   operand * result, iCode * ic, iCode *pi)
10718 {
10719   int size, offset, dopi=1;
10720   sym_link *retype = getSpec (operandType (right));
10721   sym_link *letype = getSpec (operandType (result));
10722
10723   aopOp (result, ic, FALSE, FALSE);
10724
10725   /* if the operand is already in dptr
10726      then we do nothing else we move the value to dptr */
10727   if (AOP_TYPE (result) != AOP_STR && !AOP_INDPTRn(result))
10728     {
10729       /* if this is remateriazable */
10730       if (AOP_TYPE (result) == AOP_IMMD)
10731         emitcode ("mov", "dptr,%s",
10732                   aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10733       else
10734         {
10735           /* we need to get it byte by byte */
10736           _startLazyDPSEvaluation ();
10737           if (AOP_TYPE (result) != AOP_DPTR)
10738             {
10739               emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10740               emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10741               if (options.model == MODEL_FLAT24)
10742                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10743             }
10744           else
10745             {
10746               /* We need to generate a load to DPTR indirect through DPTR. */
10747               D (emitcode (";", "genFarPointerSet -- indirection special case."););
10748
10749               emitcode ("push", "%s", aopGet (AOP (result), 0, FALSE, TRUE, NULL));
10750               emitcode ("push", "%s", aopGet (AOP (result), 1, FALSE, TRUE, NULL));
10751               if (options.model == MODEL_FLAT24)
10752                 emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10753               emitcode ("pop", "dph");
10754               emitcode ("pop", "dpl");
10755               dopi=0;
10756             }
10757           _endLazyDPSEvaluation ();
10758         }
10759     }
10760   /* so dptr know contains the address */
10761   aopOp (right, ic, FALSE, (AOP_INDPTRn(result) ? FALSE : TRUE));
10762
10763   /* if bit then unpack */
10764   if (IS_BITFIELD (retype) || IS_BITFIELD (letype)) {
10765       if (AOP_INDPTRn(result)) {
10766           genSetDPTR(AOP(result)->aopu.dptr);
10767       }
10768       genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", FPOINTER);
10769       if (AOP_INDPTRn(result)) {
10770           genSetDPTR(0);
10771       }
10772   } else {
10773       size = AOP_SIZE (right);
10774       offset = 0;
10775       if (AOP_INDPTRn(result) && AOP_USESDPTR(right)) {
10776           while (size--) {
10777               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10778
10779               genSetDPTR(AOP(result)->aopu.dptr);
10780               emitcode ("movx", "@dptr,a");
10781               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10782                   emitcode ("inc", "dptr");
10783               genSetDPTR (0);
10784           }
10785       } else {
10786           _startLazyDPSEvaluation ();
10787           while (size--) {
10788               MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10789
10790               if (AOP_INDPTRn(result)) {
10791                   genSetDPTR(AOP(result)->aopu.dptr);
10792               } else {
10793                   genSetDPTR (0);
10794               }
10795               _flushLazyDPS ();
10796
10797               emitcode ("movx", "@dptr,a");
10798               if (size || (dopi && pi && AOP_TYPE (result) != AOP_IMMD))
10799                   emitcode ("inc", "dptr");
10800           }
10801           _endLazyDPSEvaluation ();
10802       }
10803   }
10804
10805   if (dopi && pi && AOP_TYPE (result) != AOP_IMMD) {
10806       if (!AOP_INDPTRn(result)) {
10807           _startLazyDPSEvaluation ();
10808
10809           aopPut (AOP(result),"dpl",0);
10810           aopPut (AOP(result),"dph",1);
10811           if (options.model == MODEL_FLAT24)
10812               aopPut (AOP(result),"dpx",2);
10813
10814           _endLazyDPSEvaluation ();
10815       }
10816       pi->generated=1;
10817   } else if ((OP_SYMBOL(result)->ruonly || AOP_INDPTRn(result)) &&
10818              AOP_SIZE(right) > 1 &&
10819              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10820
10821       size = AOP_SIZE (right) - 1;
10822       if (AOP_INDPTRn(result)) {
10823           genSetDPTR(AOP(result)->aopu.dptr);
10824       }
10825       while (size--) emitcode ("lcall","__decdptr");
10826       if (AOP_INDPTRn(result)) {
10827           genSetDPTR(0);
10828       }
10829   }
10830   freeAsmop (result, NULL, ic, TRUE);
10831   freeAsmop (right, NULL, ic, TRUE);
10832 }
10833
10834 /*-----------------------------------------------------------------*/
10835 /* genGenPointerSet - set value from generic pointer space         */
10836 /*-----------------------------------------------------------------*/
10837 static void
10838 genGenPointerSet (operand * right,
10839                   operand * result, iCode * ic, iCode *pi)
10840 {
10841   int size, offset;
10842   sym_link *retype = getSpec (operandType (right));
10843   sym_link *letype = getSpec (operandType (result));
10844
10845   aopOp (result, ic, FALSE, AOP_IS_STR(result) ? FALSE : TRUE);
10846
10847   /* if the operand is already in dptr
10848      then we do nothing else we move the value to dptr */
10849   if (AOP_TYPE (result) != AOP_STR)
10850     {
10851       _startLazyDPSEvaluation ();
10852       /* if this is remateriazable */
10853       if (AOP_TYPE (result) == AOP_IMMD)
10854         {
10855           emitcode ("mov", "dptr,%s", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10856           if (AOP(result)->aopu.aop_immd.from_cast_remat)
10857           {
10858               MOVB(aopGet(AOP (result), AOP_SIZE(result)-1, FALSE, FALSE, NULL));
10859           }
10860           else
10861           {
10862               emitcode ("mov",
10863                         "b,%s + 1", aopGet (AOP (result), 0, TRUE, FALSE, NULL));
10864           }
10865         }
10866       else
10867         {                       /* we need to get it byte by byte */
10868           emitcode ("mov", "dpl,%s", aopGet (AOP (result), 0, FALSE, FALSE, NULL));
10869           emitcode ("mov", "dph,%s", aopGet (AOP (result), 1, FALSE, FALSE, NULL));
10870           if (options.model == MODEL_FLAT24) {
10871             emitcode ("mov", "dpx,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10872             emitcode ("mov", "b,%s", aopGet (AOP (result), 3, FALSE, FALSE, NULL));
10873           } else {
10874             emitcode ("mov", "b,%s", aopGet (AOP (result), 2, FALSE, FALSE, NULL));
10875           }
10876         }
10877       _endLazyDPSEvaluation ();
10878     }
10879   /* so dptr + b now contains the address */
10880   _G.bInUse++;
10881   aopOp (right, ic, FALSE, TRUE);
10882   _G.bInUse--;
10883
10884
10885   /* if bit then unpack */
10886   if (IS_BITFIELD (retype) || IS_BITFIELD (letype))
10887     {
10888         genPackBits ((IS_BITFIELD (retype) ? retype : letype), right, "dptr", GPOINTER);
10889     }
10890   else
10891     {
10892         size = AOP_SIZE (right);
10893         offset = 0;
10894
10895         _startLazyDPSEvaluation ();
10896         while (size--)
10897         {
10898             if (size)
10899             {
10900                 // Set two bytes at a time, passed in _AP & A.
10901                 // dptr will be incremented ONCE by __gptrputWord.
10902                 //
10903                 // Note: any change here must be coordinated
10904                 // with the implementation of __gptrputWord
10905                 // in device/lib/_gptrput.c
10906                 emitcode("mov", "_ap, %s",
10907                          aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10908                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10909
10910                 genSetDPTR (0);
10911                 _flushLazyDPS ();
10912                 emitcode ("lcall", "__gptrputWord");
10913                 size--;
10914             }
10915             else
10916             {
10917                 // Only one byte to put.
10918                 MOVA (aopGet (AOP (right), offset++, FALSE, FALSE, NULL));
10919
10920                 genSetDPTR (0);
10921                 _flushLazyDPS ();
10922                 emitcode ("lcall", "__gptrput");
10923             }
10924
10925             if (size || (pi && AOP_TYPE (result) != AOP_IMMD))
10926             {
10927                 emitcode ("inc", "dptr");
10928             }
10929         }
10930         _endLazyDPSEvaluation ();
10931     }
10932
10933   if (pi && AOP_TYPE (result) != AOP_IMMD) {
10934       _startLazyDPSEvaluation ();
10935
10936       aopPut (AOP(result),"dpl",0);
10937       aopPut (AOP(result),"dph",1);
10938       if (options.model == MODEL_FLAT24) {
10939           aopPut (AOP(result),"dpx",2);
10940           aopPut (AOP(result),"b",3);
10941       } else {
10942           aopPut (AOP(result),"b",2);
10943       }
10944       _endLazyDPSEvaluation ();
10945
10946       pi->generated=1;
10947   } else if (OP_SYMBOL(result)->ruonly && AOP_SIZE(right) > 1 &&
10948              (OP_SYMBOL (result)->liveTo > ic->seq || ic->depth)) {
10949
10950       size = AOP_SIZE (right) - 1;
10951       while (size--) emitcode ("lcall","__decdptr");
10952   }
10953   freeAsmop (result, NULL, ic, TRUE);
10954   freeAsmop (right, NULL, ic, TRUE);
10955 }
10956
10957 /*-----------------------------------------------------------------*/
10958 /* genPointerSet - stores the value into a pointer location        */
10959 /*-----------------------------------------------------------------*/
10960 static void
10961 genPointerSet (iCode * ic, iCode *pi)
10962 {
10963   operand *right, *result;
10964   sym_link *type, *etype;
10965   int p_type;
10966
10967   D (emitcode (";", "genPointerSet "););
10968
10969   right = IC_RIGHT (ic);
10970   result = IC_RESULT (ic);
10971
10972   /* depending on the type of pointer we need to
10973      move it to the correct pointer register */
10974   type = operandType (result);
10975   etype = getSpec (type);
10976   /* if left is of type of pointer then it is simple */
10977   if (IS_PTR (type) && !IS_FUNC (type->next))
10978     {
10979       p_type = DCL_TYPE (type);
10980     }
10981   else
10982     {
10983       /* we have to go by the storage class */
10984       p_type = PTR_TYPE (SPEC_OCLS (etype));
10985     }
10986   /* special case when cast remat */
10987   if (p_type == GPOINTER && OP_SYMBOL(result)->remat &&
10988       IS_CAST_ICODE(OP_SYMBOL(result)->rematiCode)) {
10989           result = IC_RIGHT(OP_SYMBOL(result)->rematiCode);
10990           type = operandType (result);
10991           p_type = DCL_TYPE (type);
10992   }
10993
10994   /* now that we have the pointer type we assign
10995      the pointer values */
10996   switch (p_type)
10997     {
10998
10999     case POINTER:
11000     case IPOINTER:
11001       genNearPointerSet (right, result, ic, pi);
11002       break;
11003
11004     case PPOINTER:
11005       genPagedPointerSet (right, result, ic, pi);
11006       break;
11007
11008     case FPOINTER:
11009       genFarPointerSet (right, result, ic, pi);
11010       break;
11011
11012     case GPOINTER:
11013       genGenPointerSet (right, result, ic, pi);
11014       break;
11015
11016     default:
11017       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11018               "genPointerSet: illegal pointer type");
11019     }
11020
11021 }
11022
11023 /*-----------------------------------------------------------------*/
11024 /* genIfx - generate code for Ifx statement                        */
11025 /*-----------------------------------------------------------------*/
11026 static void
11027 genIfx (iCode * ic, iCode * popIc)
11028 {
11029   operand *cond = IC_COND (ic);
11030   int isbit = 0;
11031
11032   D (emitcode (";", "genIfx "););
11033
11034   aopOp (cond, ic, FALSE, FALSE);
11035
11036   /* get the value into acc */
11037   if (AOP_TYPE (cond) != AOP_CRY)
11038     {
11039         toBoolean (cond);
11040     }
11041   else
11042     {
11043         isbit = 1;
11044     }
11045
11046   /* the result is now in the accumulator */
11047   freeAsmop (cond, NULL, ic, TRUE);
11048
11049   /* if there was something to be popped then do it */
11050   if (popIc)
11051     genIpop (popIc);
11052
11053   /* if the condition is  a bit variable */
11054   if (isbit && IS_ITEMP (cond) &&
11055       SPIL_LOC (cond))
11056     {
11057         genIfxJump (ic, SPIL_LOC (cond)->rname);
11058     }
11059   else if (isbit && !IS_ITEMP (cond))
11060     {
11061         genIfxJump (ic, OP_SYMBOL (cond)->rname);
11062     }
11063   else
11064     {
11065         genIfxJump (ic, "a");
11066     }
11067
11068   ic->generated = 1;
11069 }
11070
11071 /*-----------------------------------------------------------------*/
11072 /* genAddrOf - generates code for address of                       */
11073 /*-----------------------------------------------------------------*/
11074 static void
11075 genAddrOf (iCode * ic)
11076 {
11077   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
11078   int size, offset;
11079
11080   D (emitcode (";", "genAddrOf ");
11081     );
11082
11083   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11084
11085   /* if the operand is on the stack then we
11086      need to get the stack offset of this
11087      variable */
11088   if (sym->onStack) {
11089
11090       /* if 10 bit stack */
11091       if (options.stack10bit) {
11092           char buff[10];
11093           int  offset;
11094
11095           tsprintf(buff, sizeof(buff),
11096                    "#!constbyte",(options.stack_loc >> 16) & 0xff);
11097           /* if it has an offset then we need to compute it */
11098 /*        emitcode ("subb", "a,#!constbyte", */
11099 /*                  -((sym->stack < 0) ? */
11100 /*                    ((short) (sym->stack - _G.nRegsSaved)) : */
11101 /*                    ((short) sym->stack)) & 0xff); */
11102 /*        emitcode ("mov","b,a"); */
11103 /*        emitcode ("mov","a,#!constbyte",(-((sym->stack < 0) ? */
11104 /*                                       ((short) (sym->stack - _G.nRegsSaved)) : */
11105 /*                                       ((short) sym->stack)) >> 8) & 0xff); */
11106           if (sym->stack) {
11107               emitcode ("mov", "a,_bpx");
11108               emitcode ("add", "a,#!constbyte", ((sym->stack < 0) ?
11109                                              ((char) (sym->stack - _G.nRegsSaved)) :
11110                                              ((char) sym->stack )) & 0xff);
11111               emitcode ("mov", "b,a");
11112               emitcode ("mov", "a,_bpx+1");
11113
11114               offset = (((sym->stack < 0) ?
11115                          ((short) (sym->stack - _G.nRegsSaved)) :
11116                          ((short) sym->stack )) >> 8) & 0xff;
11117
11118               emitcode ("addc","a,#!constbyte", offset);
11119
11120               aopPut (AOP (IC_RESULT (ic)), "b", 0);
11121               aopPut (AOP (IC_RESULT (ic)), "a", 1);
11122               aopPut (AOP (IC_RESULT (ic)), buff, 2);
11123           } else {
11124               /* we can just move _bp */
11125               aopPut (AOP (IC_RESULT (ic)), "_bpx", 0);
11126               aopPut (AOP (IC_RESULT (ic)), "_bpx+1", 1);
11127               aopPut (AOP (IC_RESULT (ic)), buff, 2);
11128           }
11129       } else {
11130           /* if it has an offset then we need to compute it */
11131           if (sym->stack) {
11132               emitcode ("mov", "a,_bp");
11133               emitcode ("add", "a,#!constbyte", ((char) sym->stack & 0xff));
11134               aopPut (AOP (IC_RESULT (ic)), "a", 0);
11135           } else {
11136               /* we can just move _bp */
11137               aopPut (AOP (IC_RESULT (ic)), "_bp", 0);
11138           }
11139           /* fill the result with zero */
11140           size = AOP_SIZE (IC_RESULT (ic)) - 1;
11141
11142
11143           if (options.stack10bit && size < (FPTRSIZE - 1)) {
11144               fprintf (stderr,
11145                        "*** warning: pointer to stack var truncated.\n");
11146           }
11147
11148           offset = 1;
11149           while (size--) {
11150               aopPut (AOP (IC_RESULT (ic)), zero, offset++);
11151           }
11152       }
11153       goto release;
11154   }
11155
11156   /* object not on stack then we need the name */
11157   size = AOP_SIZE (IC_RESULT (ic));
11158   offset = 0;
11159
11160   while (size--)
11161     {
11162       char s[SDCC_NAME_MAX];
11163       if (offset) {
11164           switch (offset) {
11165           case 1:
11166               tsprintf(s, sizeof(s), "#!his",sym->rname);
11167               break;
11168           case 2:
11169               tsprintf(s, sizeof(s), "#!hihis",sym->rname);
11170               break;
11171           case 3:
11172               tsprintf(s, sizeof(s), "#!hihihis",sym->rname);
11173               break;
11174           default: /* should not need this (just in case) */
11175               SNPRINTF (s, sizeof(s), "#(%s >> %d)",
11176                        sym->rname,
11177                        offset * 8);
11178           }
11179       }
11180       else
11181       {
11182           SNPRINTF (s, sizeof(s), "#%s", sym->rname);
11183       }
11184
11185       aopPut (AOP (IC_RESULT (ic)), s, offset++);
11186     }
11187
11188 release:
11189   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11190
11191 }
11192
11193 #if 0 // obsolete, and buggy for != xdata
11194 /*-----------------------------------------------------------------*/
11195 /* genArrayInit - generates code for address of                       */
11196 /*-----------------------------------------------------------------*/
11197 static void
11198 genArrayInit (iCode * ic)
11199 {
11200     literalList *iLoop;
11201     int         ix, count;
11202     int         elementSize = 0, eIndex;
11203     unsigned    val, lastVal;
11204     sym_link    *type;
11205     operand     *left=IC_LEFT(ic);
11206
11207     D (emitcode (";", "genArrayInit "););
11208
11209     aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
11210
11211     if (AOP_TYPE(IC_LEFT(ic)) == AOP_IMMD)
11212     {
11213         // Load immediate value into DPTR.
11214         emitcode("mov", "dptr, %s",
11215              aopGet(AOP(IC_LEFT(ic)), 0, TRUE, FALSE, NULL));
11216     }
11217     else if (AOP_TYPE(IC_LEFT(ic)) != AOP_DPTR)
11218     {
11219 #if 0
11220       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11221               "Unexpected operand to genArrayInit.\n");
11222       exit(1);
11223 #else
11224       // a regression because of SDCCcse.c:1.52
11225       emitcode ("mov", "dpl,%s", aopGet (AOP (left), 0, FALSE, FALSE, NULL));
11226       emitcode ("mov", "dph,%s", aopGet (AOP (left), 1, FALSE, FALSE, NULL));
11227       if (options.model == MODEL_FLAT24)
11228         emitcode ("mov", "dpx,%s", aopGet (AOP (left), 2, FALSE, FALSE, NULL));
11229 #endif
11230     }
11231
11232     type = operandType(IC_LEFT(ic));
11233
11234     if (type && type->next)
11235     {
11236         elementSize = getSize(type->next);
11237     }
11238     else
11239     {
11240         werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11241                                 "can't determine element size in genArrayInit.\n");
11242         exit(1);
11243     }
11244
11245     iLoop = IC_ARRAYILIST(ic);
11246     lastVal = 0xffff;
11247
11248     while (iLoop)
11249     {
11250         bool firstpass = TRUE;
11251
11252         emitcode(";", "store %d x 0x%x to DPTR (element size %d)",
11253                  iLoop->count, (int)iLoop->literalValue, elementSize);
11254
11255         ix = iLoop->count;
11256
11257         while (ix)
11258         {
11259             symbol *tlbl = NULL;
11260
11261             count = ix > 256 ? 256 : ix;
11262
11263             if (count > 1)
11264             {
11265                 tlbl = newiTempLabel (NULL);
11266                 if (firstpass || (count & 0xff))
11267                 {
11268                     emitcode("mov", "b, #!constbyte", count & 0xff);
11269                 }
11270
11271                 emitcode ("", "!tlabeldef", tlbl->key + 100);
11272             }
11273
11274             firstpass = FALSE;
11275
11276             for (eIndex = 0; eIndex < elementSize; eIndex++)
11277             {
11278                 val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
11279                 if (val != lastVal)
11280                 {
11281                     emitcode("mov", "a, #!constbyte", val);
11282                     lastVal = val;
11283                 }
11284
11285                 emitcode("movx", "@dptr, a");
11286                 emitcode("inc", "dptr");
11287             }
11288
11289             if (count > 1)
11290             {
11291                 emitcode("djnz", "b, !tlabel", tlbl->key + 100);
11292             }
11293
11294             ix -= count;
11295         }
11296
11297         iLoop = iLoop->next;
11298     }
11299
11300     freeAsmop (IC_LEFT(ic), NULL, ic, TRUE);
11301 }
11302 #endif
11303
11304 /*-----------------------------------------------------------------*/
11305 /* genFarFarAssign - assignment when both are in far space         */
11306 /*-----------------------------------------------------------------*/
11307 static void
11308 genFarFarAssign (operand * result, operand * right, iCode * ic)
11309 {
11310   int size = AOP_SIZE (right);
11311   int offset = 0;
11312   symbol *rSym = NULL;
11313
11314   if (size == 1)
11315   {
11316       /* quick & easy case. */
11317       D(emitcode(";","genFarFarAssign (1 byte case)"););
11318       MOVA(aopGet(AOP(right), 0, FALSE, FALSE, NULL));
11319       freeAsmop (right, NULL, ic, FALSE);
11320       /* now assign DPTR to result */
11321       _G.accInUse++;
11322       aopOp(result, ic, FALSE, FALSE);
11323       _G.accInUse--;
11324       aopPut(AOP(result), "a", 0);
11325       freeAsmop(result, NULL, ic, FALSE);
11326       return;
11327   }
11328
11329   /* See if we've got an underlying symbol to abuse. */
11330   if (IS_SYMOP(result) && OP_SYMBOL(result))
11331   {
11332       if (IS_TRUE_SYMOP(result))
11333       {
11334           rSym = OP_SYMBOL(result);
11335       }
11336       else if (IS_ITEMP(result) && OP_SYMBOL(result)->isspilt && OP_SYMBOL(result)->usl.spillLoc)
11337       {
11338           rSym = OP_SYMBOL(result)->usl.spillLoc;
11339       }
11340   }
11341
11342   if (size > 1 && rSym && rSym->rname && !rSym->onStack)
11343   {
11344       /* We can use the '390 auto-toggle feature to good effect here. */
11345
11346       D(emitcode(";","genFarFarAssign (390 auto-toggle fun)"););
11347       emitcode("mov", "dps,#!constbyte",0x21);  /* Select DPTR2 & auto-toggle. */
11348       emitcode ("mov", "dptr,#%s", rSym->rname);
11349       /* DP2 = result, DP1 = right, DP1 is current. */
11350       while (size)
11351       {
11352           emitcode("movx", "a,@dptr");
11353           emitcode("movx", "@dptr,a");
11354           if (--size)
11355           {
11356                emitcode("inc", "dptr");
11357                emitcode("inc", "dptr");
11358           }
11359       }
11360       emitcode("mov", "dps,#0");
11361       freeAsmop (right, NULL, ic, FALSE);
11362 #if 0
11363 some alternative code for processors without auto-toggle
11364 no time to test now, so later well put in...kpb
11365         D(emitcode(";","genFarFarAssign (dual-dptr fun)"););
11366         emitcode("mov", "dps,#1");      /* Select DPTR2. */
11367         emitcode ("mov", "dptr,#%s", rSym->rname);
11368         /* DP2 = result, DP1 = right, DP1 is current. */
11369         while (size)
11370         {
11371           --size;
11372           emitcode("movx", "a,@dptr");
11373           if (size)
11374             emitcode("inc", "dptr");
11375           emitcode("inc", "dps");
11376           emitcode("movx", "@dptr,a");
11377           if (size)
11378             emitcode("inc", "dptr");
11379           emitcode("inc", "dps");
11380         }
11381         emitcode("mov", "dps,#0");
11382         freeAsmop (right, NULL, ic, FALSE);
11383 #endif
11384   }
11385   else
11386   {
11387       D (emitcode (";", "genFarFarAssign"););
11388       aopOp (result, ic, TRUE, TRUE);
11389
11390       _startLazyDPSEvaluation ();
11391
11392       while (size--)
11393         {
11394           aopPut (AOP (result),
11395                   aopGet (AOP (right), offset, FALSE, FALSE, NULL), offset);
11396           offset++;
11397         }
11398       _endLazyDPSEvaluation ();
11399       freeAsmop (result, NULL, ic, FALSE);
11400       freeAsmop (right, NULL, ic, FALSE);
11401   }
11402 }
11403
11404 /*-----------------------------------------------------------------*/
11405 /* genAssign - generate code for assignment                        */
11406 /*-----------------------------------------------------------------*/
11407 static void
11408 genAssign (iCode * ic)
11409 {
11410   operand *result, *right;
11411   int size, offset;
11412   unsigned long lit = 0L;
11413
11414   D (emitcode (";", "genAssign ");
11415     );
11416
11417   result = IC_RESULT (ic);
11418   right = IC_RIGHT (ic);
11419
11420   /* if they are the same */
11421   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11422     return;
11423
11424   aopOp (right, ic, FALSE, FALSE);
11425
11426   emitcode (";", "genAssign: resultIsFar = %s",
11427             isOperandInFarSpace (result) ?
11428             "TRUE" : "FALSE");
11429
11430   /* special case both in far space */
11431   if ((AOP_TYPE (right) == AOP_DPTR ||
11432        AOP_TYPE (right) == AOP_DPTR2) &&
11433   /* IS_TRUE_SYMOP(result)       && */
11434       isOperandInFarSpace (result))
11435     {
11436       genFarFarAssign (result, right, ic);
11437       return;
11438     }
11439
11440   aopOp (result, ic, TRUE, FALSE);
11441
11442   /* if they are the same registers */
11443   if (sameRegs (AOP (right), AOP (result)))
11444     goto release;
11445
11446   /* if the result is a bit */
11447   if (AOP_TYPE (result) == AOP_CRY) /* works only for true symbols */
11448     {
11449       /* if the right size is a literal then
11450          we know what the value is */
11451       if (AOP_TYPE (right) == AOP_LIT)
11452         {
11453           if (((int) operandLitValue (right)))
11454             aopPut (AOP (result), one, 0);
11455           else
11456             aopPut (AOP (result), zero, 0);
11457           goto release;
11458         }
11459
11460       /* the right is also a bit variable */
11461       if (AOP_TYPE (right) == AOP_CRY)
11462         {
11463           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11464           aopPut (AOP (result), "c", 0);
11465           goto release;
11466         }
11467
11468       /* we need to or */
11469       toBoolean (right);
11470       aopPut (AOP (result), "a", 0);
11471       goto release;
11472     }
11473
11474   /* bit variables done */
11475   /* general case */
11476   size = AOP_SIZE (result);
11477   offset = 0;
11478   if (AOP_TYPE (right) == AOP_LIT)
11479     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
11480
11481   if ((size > 1) &&
11482       (AOP_TYPE (result) != AOP_REG) &&
11483       (AOP_TYPE (right) == AOP_LIT) &&
11484       !IS_FLOAT (operandType (right)))
11485     {
11486       _startLazyDPSEvaluation ();
11487       while (size && ((unsigned int) (lit >> (offset * 8)) != 0))
11488         {
11489           aopPut (AOP (result),
11490                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11491                   offset);
11492           offset++;
11493           size--;
11494         }
11495       /* And now fill the rest with zeros. */
11496       if (size)
11497         {
11498           emitcode ("clr", "a");
11499         }
11500       while (size--)
11501         {
11502           aopPut (AOP (result), "a", offset++);
11503         }
11504       _endLazyDPSEvaluation ();
11505     }
11506   else
11507     {
11508       _startLazyDPSEvaluation ();
11509       while (size--)
11510         {
11511           aopPut (AOP (result),
11512                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11513                   offset);
11514           offset++;
11515         }
11516       _endLazyDPSEvaluation ();
11517     }
11518
11519 release:
11520   freeAsmop (right, NULL, ic, FALSE);
11521   freeAsmop (result, NULL, ic, TRUE);
11522 }
11523
11524 /*-----------------------------------------------------------------*/
11525 /* genJumpTab - generates code for jump table                      */
11526 /*-----------------------------------------------------------------*/
11527 static void
11528 genJumpTab (iCode * ic)
11529 {
11530   symbol *jtab;
11531   char *l;
11532
11533   D (emitcode (";", "genJumpTab ");
11534     );
11535
11536   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
11537   /* get the condition into accumulator */
11538   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE, FALSE, NULL);
11539   MOVA (l);
11540   /* multiply by four! */
11541   emitcode ("add", "a,acc");
11542   emitcode ("add", "a,acc");
11543   freeAsmop (IC_JTCOND (ic), NULL, ic, TRUE);
11544
11545   jtab = newiTempLabel (NULL);
11546   emitcode ("mov", "dptr,#!tlabel", jtab->key + 100);
11547   emitcode ("jmp", "@a+dptr");
11548   emitcode ("", "!tlabeldef", jtab->key + 100);
11549   /* now generate the jump labels */
11550   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
11551        jtab = setNextItem (IC_JTLABELS (ic)))
11552     emitcode ("ljmp", "!tlabel", jtab->key + 100);
11553
11554 }
11555
11556 /*-----------------------------------------------------------------*/
11557 /* genCast - gen code for casting                                  */
11558 /*-----------------------------------------------------------------*/
11559 static void
11560 genCast (iCode * ic)
11561 {
11562   operand *result = IC_RESULT (ic);
11563   sym_link *ctype = operandType (IC_LEFT (ic));
11564   sym_link *rtype = operandType (IC_RIGHT (ic));
11565   operand *right = IC_RIGHT (ic);
11566   int size, offset;
11567
11568   D (emitcode (";", "genCast "););
11569
11570   /* if they are equivalent then do nothing */
11571   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11572     return;
11573
11574   aopOp (right, ic, FALSE, AOP_IS_STR (result));
11575   aopOp (result, ic, FALSE, (AOP_TYPE(right) == AOP_DPTR));
11576
11577   /* if the result is a bit */
11578   if (IS_BITVAR (OP_SYMBOL (result)->type)
11579       && !IS_BITFIELD (OP_SYMBOL (result)->type) )
11580     {
11581       /* if the right size is a literal then
11582          we know what the value is */
11583       if (AOP_TYPE (right) == AOP_LIT)
11584         {
11585           if (((int) operandLitValue (right)))
11586             aopPut (AOP (result), one, 0);
11587           else
11588             aopPut (AOP (result), zero, 0);
11589
11590           goto release;
11591         }
11592
11593       /* the right is also a bit variable */
11594       if (AOP_TYPE (right) == AOP_CRY)
11595         {
11596           emitcode ("mov", "c,%s", AOP (right)->aopu.aop_dir);
11597           aopPut (AOP (result), "c", 0);
11598           goto release;
11599         }
11600
11601       /* we need to or */
11602       toBoolean (right);
11603       aopPut (AOP (result), "a", 0);
11604       goto release;
11605     }
11606
11607   /* if they are the same size : or less */
11608   if (AOP_SIZE (result) <= AOP_SIZE (right))
11609     {
11610
11611       /* if they are in the same place */
11612       if (sameRegs (AOP (right), AOP (result)))
11613         goto release;
11614
11615       /* if they in different places then copy */
11616       size = AOP_SIZE (result);
11617       offset = 0;
11618       _startLazyDPSEvaluation ();
11619       while (size--)
11620         {
11621           aopPut (AOP (result),
11622                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11623                   offset);
11624           offset++;
11625         }
11626       _endLazyDPSEvaluation ();
11627       goto release;
11628     }
11629
11630
11631   /* if the result is of type pointer */
11632   if (IS_PTR (ctype))
11633     {
11634
11635       int p_type;
11636       sym_link *type = operandType (right);
11637
11638       /* pointer to generic pointer */
11639       if (IS_GENPTR (ctype))
11640         {
11641           if (IS_PTR (type))
11642             {
11643               p_type = DCL_TYPE (type);
11644             }
11645           else
11646             {
11647 #if OLD_CAST_BEHAVIOR
11648               /* KV: we are converting a non-pointer type to
11649                * a generic pointer. This (ifdef'd out) code
11650                * says that the resulting generic pointer
11651                * should have the same class as the storage
11652                * location of the non-pointer variable.
11653                *
11654                * For example, converting an int (which happens
11655                * to be stored in DATA space) to a pointer results
11656                * in a DATA generic pointer; if the original int
11657                * in XDATA space, so will be the resulting pointer.
11658                *
11659                * I don't like that behavior, and thus this change:
11660                * all such conversions will be forced to XDATA and
11661                * throw a warning. If you want some non-XDATA
11662                * type, or you want to suppress the warning, you
11663                * must go through an intermediate cast, like so:
11664                *
11665                * char _generic *gp = (char _xdata *)(intVar);
11666                */
11667               sym_link *etype = getSpec (type);
11668
11669               /* we have to go by the storage class */
11670               if (SPEC_OCLS (etype) != generic)
11671                 {
11672                   p_type = PTR_TYPE (SPEC_OCLS (etype));
11673                 }
11674               else
11675 #endif
11676                 {
11677                   /* Converting unknown class (i.e. register variable)
11678                    * to generic pointer. This is not good, but
11679                    * we'll make a guess (and throw a warning).
11680                    */
11681                   p_type = FPOINTER;
11682                   werror (W_INT_TO_GEN_PTR_CAST);
11683                 }
11684             }
11685
11686           /* the first two bytes are known */
11687           size = GPTRSIZE - 1;
11688           offset = 0;
11689           _startLazyDPSEvaluation ();
11690           while (size--)
11691             {
11692               aopPut (AOP (result),
11693                       aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11694                       offset);
11695               offset++;
11696             }
11697           _endLazyDPSEvaluation ();
11698
11699           /* the last byte depending on type */
11700             {
11701                 int gpVal = pointerTypeToGPByte(p_type, NULL, NULL);
11702                 char gpValStr[10];
11703
11704                 if (gpVal == -1)
11705                 {
11706                     // pointerTypeToGPByte will have bitched.
11707                     exit(1);
11708                 }
11709
11710                 SNPRINTF(gpValStr, sizeof(gpValStr), "#0x%d", gpVal);
11711                 aopPut (AOP (result), gpValStr, GPTRSIZE - 1);
11712             }
11713           goto release;
11714         }
11715
11716       /* just copy the pointers */
11717       size = AOP_SIZE (result);
11718       offset = 0;
11719       _startLazyDPSEvaluation ();
11720       while (size--)
11721         {
11722           aopPut (AOP (result),
11723                   aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11724                   offset);
11725           offset++;
11726         }
11727       _endLazyDPSEvaluation ();
11728       goto release;
11729     }
11730
11731   /* so we now know that the size of destination is greater
11732      than the size of the source */
11733   /* we move to result for the size of source */
11734   size = AOP_SIZE (right);
11735   offset = 0;
11736   _startLazyDPSEvaluation ();
11737   while (size--)
11738     {
11739       aopPut (AOP (result),
11740               aopGet (AOP (right), offset, FALSE, FALSE, NULL),
11741               offset);
11742       offset++;
11743     }
11744   _endLazyDPSEvaluation ();
11745
11746   /* now depending on the sign of the source && destination */
11747   size = AOP_SIZE (result) - AOP_SIZE (right);
11748   /* if unsigned or not an integral type */
11749   /* also, if the source is a bit, we don't need to sign extend, because
11750    * it can't possibly have set the sign bit.
11751    */
11752   if (!IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
11753     {
11754       while (size--)
11755         {
11756           aopPut (AOP (result), zero, offset++);
11757         }
11758     }
11759   else
11760     {
11761       /* we need to extend the sign :{ */
11762       MOVA (aopGet (AOP (right), AOP_SIZE (right) - 1,
11763                         FALSE, FALSE, NULL));
11764       emitcode ("rlc", "a");
11765       emitcode ("subb", "a,acc");
11766       while (size--)
11767         aopPut (AOP (result), "a", offset++);
11768     }
11769
11770   /* we are done hurray !!!! */
11771
11772 release:
11773   freeAsmop (right, NULL, ic, TRUE);
11774   freeAsmop (result, NULL, ic, TRUE);
11775
11776 }
11777
11778 /*-----------------------------------------------------------------*/
11779 /* genDjnz - generate decrement & jump if not zero instrucion      */
11780 /*-----------------------------------------------------------------*/
11781 static int
11782 genDjnz (iCode * ic, iCode * ifx)
11783 {
11784   symbol *lbl, *lbl1;
11785   if (!ifx)
11786     return 0;
11787
11788   /* if the if condition has a false label
11789      then we cannot save */
11790   if (IC_FALSE (ifx))
11791     return 0;
11792
11793   /* if the minus is not of the form
11794      a = a - 1 */
11795   if (!isOperandEqual (IC_RESULT (ic), IC_LEFT (ic)) ||
11796       !IS_OP_LITERAL (IC_RIGHT (ic)))
11797     return 0;
11798
11799   if (operandLitValue (IC_RIGHT (ic)) != 1)
11800     return 0;
11801
11802   /* if the size of this greater than one then no
11803      saving */
11804   if (getSize (operandType (IC_RESULT (ic))) > 1)
11805     return 0;
11806
11807   /* otherwise we can save BIG */
11808   D(emitcode(";", "genDjnz"););
11809
11810   lbl = newiTempLabel (NULL);
11811   lbl1 = newiTempLabel (NULL);
11812
11813   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11814
11815   if (AOP_NEEDSACC(IC_RESULT(ic)))
11816   {
11817       /* If the result is accessed indirectly via
11818        * the accumulator, we must explicitly write
11819        * it back after the decrement.
11820        */
11821       char *rByte = aopGet(AOP(IC_RESULT(ic)), 0, FALSE, FALSE, NULL);
11822
11823       if (strcmp(rByte, "a"))
11824       {
11825            /* Something is hopelessly wrong */
11826            fprintf(stderr, "*** warning: internal error at %s:%d\n",
11827                    __FILE__, __LINE__);
11828            /* We can just give up; the generated code will be inefficient,
11829             * but what the hey.
11830             */
11831            freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11832            return 0;
11833       }
11834       emitcode ("dec", "%s", rByte);
11835       aopPut(AOP(IC_RESULT(ic)), rByte, 0);
11836       emitcode ("jnz", "!tlabel", lbl->key + 100);
11837   }
11838   else if (IS_AOP_PREG (IC_RESULT (ic)))
11839     {
11840       emitcode ("dec", "%s",
11841                 aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11842       emitcode ("mov", "a,%s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, FALSE, NULL));
11843       emitcode ("jnz", "!tlabel", lbl->key + 100);
11844     }
11845   else
11846     {
11847       emitcode ("djnz", "%s,!tlabel", aopGet (AOP (IC_RESULT (ic)), 0, FALSE, TRUE, NULL),
11848                 lbl->key + 100);
11849     }
11850   emitcode ("sjmp", "!tlabel", lbl1->key + 100);
11851   emitcode ("", "!tlabeldef", lbl->key + 100);
11852   emitcode ("ljmp", "!tlabel", IC_TRUE (ifx)->key + 100);
11853   emitcode ("", "!tlabeldef", lbl1->key + 100);
11854
11855   freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11856   ifx->generated = 1;
11857   return 1;
11858 }
11859
11860 /*-----------------------------------------------------------------*/
11861 /* genReceive - generate code for a receive iCode                  */
11862 /*-----------------------------------------------------------------*/
11863 static void
11864 genReceive (iCode * ic)
11865 {
11866     int size = getSize (operandType (IC_RESULT (ic)));
11867     int offset = 0;
11868     int rb1off ;
11869
11870     D (emitcode (";", "genReceive "););
11871
11872     if (ic->argreg == 1)
11873     {
11874         /* first parameter */
11875         if (AOP_IS_STR(IC_RESULT(ic)))
11876         {
11877             /* Nothing to do: it's already in the proper place. */
11878             return;
11879         }
11880         else
11881         {
11882             bool useDp2;
11883
11884             useDp2 = isOperandInFarSpace (IC_RESULT (ic)) &&
11885                 (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
11886                  IS_TRUE_SYMOP (IC_RESULT (ic)));
11887
11888             _G.accInUse++;
11889             aopOp (IC_RESULT (ic), ic, FALSE, useDp2);
11890             _G.accInUse--;
11891
11892             /* Sanity checking... */
11893             if (AOP_USESDPTR(IC_RESULT(ic)))
11894             {
11895                 werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
11896                         "genReceive got unexpected DPTR.");
11897             }
11898             assignResultValue (IC_RESULT (ic));
11899         }
11900     }
11901     else
11902     {
11903         /* second receive onwards */
11904         /* this gets a little tricky since unused recevies will be
11905          eliminated, we have saved the reg in the type field . and
11906          we use that to figure out which register to use */
11907         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11908         rb1off = ic->argreg;
11909         while (size--)
11910         {
11911             aopPut (AOP (IC_RESULT (ic)), rb1regs[rb1off++ -5], offset++);
11912         }
11913     }
11914     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
11915 }
11916
11917 /*-----------------------------------------------------------------*/
11918 /* genMemcpyX2X - gen code for memcpy xdata to xdata               */
11919 /*-----------------------------------------------------------------*/
11920 static void genMemcpyX2X( iCode *ic, int nparms, operand **parms, int fromc)
11921 {
11922     operand *from , *to , *count;
11923     symbol *lbl;
11924     bitVect *rsave;
11925     int i;
11926
11927     /* we know it has to be 3 parameters */
11928     assert (nparms == 3);
11929
11930     rsave = newBitVect(16);
11931     /* save DPTR if it needs to be saved */
11932     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
11933             if (bitVectBitValue(ic->rMask,i))
11934                     rsave = bitVectSetBit(rsave,i);
11935     }
11936     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
11937                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
11938     savermask(rsave);
11939
11940     to = parms[0];
11941     from = parms[1];
11942     count = parms[2];
11943
11944     aopOp (from, ic->next, FALSE, FALSE);
11945
11946     /* get from into DPTR1 */
11947     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
11948     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
11949     if (options.model == MODEL_FLAT24) {
11950         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
11951     }
11952
11953     freeAsmop (from, NULL, ic, FALSE);
11954     aopOp (to, ic, FALSE, FALSE);
11955     /* get "to" into DPTR */
11956     /* if the operand is already in dptr
11957        then we do nothing else we move the value to dptr */
11958     if (AOP_TYPE (to) != AOP_STR) {
11959         /* if already in DPTR then we need to push */
11960         if (AOP_TYPE(to) == AOP_DPTR) {
11961             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
11962             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
11963             if (options.model == MODEL_FLAT24)
11964                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11965             emitcode ("pop", "dph");
11966             emitcode ("pop", "dpl");
11967         } else {
11968             _startLazyDPSEvaluation ();
11969             /* if this is remateriazable */
11970             if (AOP_TYPE (to) == AOP_IMMD) {
11971                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
11972             } else {                    /* we need to get it byte by byte */
11973                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
11974                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
11975                 if (options.model == MODEL_FLAT24) {
11976                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
11977                 }
11978             }
11979             _endLazyDPSEvaluation ();
11980         }
11981     }
11982     freeAsmop (to, NULL, ic, FALSE);
11983     _G.dptrInUse = _G.dptr1InUse = 1;
11984     aopOp (count, ic->next->next, FALSE,FALSE);
11985     lbl =newiTempLabel(NULL);
11986
11987     /* now for the actual copy */
11988     if (AOP_TYPE(count) == AOP_LIT &&
11989         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
11990         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
11991         if (fromc) {
11992             emitcode ("lcall","__bi_memcpyc2x_s");
11993         } else {
11994             emitcode ("lcall","__bi_memcpyx2x_s");
11995         }
11996         freeAsmop (count, NULL, ic, FALSE);
11997     } else {
11998         symbol *lbl1 = newiTempLabel(NULL);
11999
12000         emitcode (";"," Auto increment but no djnz");
12001         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12002         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12003         freeAsmop (count, NULL, ic, FALSE);
12004         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12005         emitcode ("","!tlabeldef",lbl->key+100);
12006         if (fromc) {
12007             emitcode ("clr","a");
12008             emitcode ("movc", "a,@a+dptr");
12009         } else
12010             emitcode ("movx", "a,@dptr");
12011         emitcode ("movx", "@dptr,a");
12012         emitcode ("inc", "dptr");
12013         emitcode ("inc", "dptr");
12014         emitcode ("mov","a,b");
12015         emitcode ("orl","a,_ap");
12016         emitcode ("jz","!tlabel",lbl1->key+100);
12017         emitcode ("mov","a,_ap");
12018         emitcode ("add","a,#!constbyte",0xFF);
12019         emitcode ("mov","_ap,a");
12020         emitcode ("mov","a,b");
12021         emitcode ("addc","a,#!constbyte",0xFF);
12022         emitcode ("mov","b,a");
12023         emitcode ("sjmp","!tlabel",lbl->key+100);
12024         emitcode ("","!tlabeldef",lbl1->key+100);
12025     }
12026     emitcode ("mov", "dps,#0");
12027     _G.dptrInUse = _G.dptr1InUse = 0;
12028     unsavermask(rsave);
12029
12030 }
12031
12032 /*-----------------------------------------------------------------*/
12033 /* genMemcmpX2X - gen code for memcmp xdata to xdata               */
12034 /*-----------------------------------------------------------------*/
12035 static void genMemcmpX2X( iCode *ic, int nparms, operand **parms, int fromc)
12036 {
12037     operand *from , *to , *count;
12038     symbol *lbl,*lbl2;
12039     bitVect *rsave;
12040     int i;
12041
12042     /* we know it has to be 3 parameters */
12043     assert (nparms == 3);
12044
12045     rsave = newBitVect(16);
12046     /* save DPTR if it needs to be saved */
12047     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12048             if (bitVectBitValue(ic->rMask,i))
12049                     rsave = bitVectSetBit(rsave,i);
12050     }
12051     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12052                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12053     savermask(rsave);
12054
12055     to = parms[0];
12056     from = parms[1];
12057     count = parms[2];
12058
12059     aopOp (from, ic->next, FALSE, FALSE);
12060
12061     /* get from into DPTR1 */
12062     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12063     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12064     if (options.model == MODEL_FLAT24) {
12065         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12066     }
12067
12068     freeAsmop (from, NULL, ic, FALSE);
12069     aopOp (to, ic, FALSE, FALSE);
12070     /* get "to" into DPTR */
12071     /* if the operand is already in dptr
12072        then we do nothing else we move the value to dptr */
12073     if (AOP_TYPE (to) != AOP_STR) {
12074         /* if already in DPTR then we need to push */
12075         if (AOP_TYPE(to) == AOP_DPTR) {
12076             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12077             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12078             if (options.model == MODEL_FLAT24)
12079                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12080             emitcode ("pop", "dph");
12081             emitcode ("pop", "dpl");
12082         } else {
12083             _startLazyDPSEvaluation ();
12084             /* if this is remateriazable */
12085             if (AOP_TYPE (to) == AOP_IMMD) {
12086                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12087             } else {                    /* we need to get it byte by byte */
12088                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12089                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12090                 if (options.model == MODEL_FLAT24) {
12091                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12092                 }
12093             }
12094             _endLazyDPSEvaluation ();
12095         }
12096     }
12097     freeAsmop (to, NULL, ic, FALSE);
12098     _G.dptrInUse = _G.dptr1InUse = 1;
12099     aopOp (count, ic->next->next, FALSE,FALSE);
12100     lbl =newiTempLabel(NULL);
12101     lbl2 =newiTempLabel(NULL);
12102
12103     /* now for the actual compare */
12104     if (AOP_TYPE(count) == AOP_LIT &&
12105         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12106         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12107         if (fromc)
12108             emitcode("lcall","__bi_memcmpc2x_s");
12109         else
12110             emitcode("lcall","__bi_memcmpx2x_s");
12111         freeAsmop (count, NULL, ic, FALSE);
12112         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12113         aopPut(AOP(IC_RESULT(ic)),"a",0);
12114         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12115     } else {
12116         symbol *lbl1 = newiTempLabel(NULL);
12117
12118         emitcode("push","ar0");
12119         emitcode (";"," Auto increment but no djnz");
12120         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12121         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12122         freeAsmop (count, NULL, ic, FALSE);
12123         emitcode ("mov", "dps,#!constbyte",0x21);       /* Select DPTR2 & auto-toggle. */
12124         emitcode ("","!tlabeldef",lbl->key+100);
12125         if (fromc) {
12126             emitcode ("clr","a");
12127             emitcode ("movc", "a,@a+dptr");
12128         } else
12129             emitcode ("movx", "a,@dptr");
12130         emitcode ("mov","r0,a");
12131         emitcode ("movx", "a,@dptr");
12132         emitcode ("clr","c");
12133         emitcode ("subb","a,r0");
12134         emitcode ("jnz","!tlabel",lbl2->key+100);
12135         emitcode ("inc", "dptr");
12136         emitcode ("inc", "dptr");
12137         emitcode ("mov","a,b");
12138         emitcode ("orl","a,_ap");
12139         emitcode ("jz","!tlabel",lbl1->key+100);
12140         emitcode ("mov","a,_ap");
12141         emitcode ("add","a,#!constbyte",0xFF);
12142         emitcode ("mov","_ap,a");
12143         emitcode ("mov","a,b");
12144         emitcode ("addc","a,#!constbyte",0xFF);
12145         emitcode ("mov","b,a");
12146         emitcode ("sjmp","!tlabel",lbl->key+100);
12147         emitcode ("","!tlabeldef",lbl1->key+100);
12148         emitcode ("clr","a");
12149         emitcode ("","!tlabeldef",lbl2->key+100);
12150         aopOp (IC_RESULT(ic), ic, FALSE,FALSE);
12151         aopPut(AOP(IC_RESULT(ic)),"a",0);
12152         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12153         emitcode("pop","ar0");
12154         emitcode ("mov", "dps,#0");
12155     }
12156     _G.dptrInUse = _G.dptr1InUse = 0;
12157     unsavermask(rsave);
12158
12159 }
12160
12161 /*-----------------------------------------------------------------*/
12162 /* genInp - gen code for __builtin_inp read data from a mem mapped */
12163 /* port, first parameter output area second parameter pointer to   */
12164 /* port third parameter count                                      */
12165 /*-----------------------------------------------------------------*/
12166 static void genInp( iCode *ic, int nparms, operand **parms)
12167 {
12168     operand *from , *to , *count;
12169     symbol *lbl;
12170     bitVect *rsave;
12171     int i;
12172
12173     /* we know it has to be 3 parameters */
12174     assert (nparms == 3);
12175
12176     rsave = newBitVect(16);
12177     /* save DPTR if it needs to be saved */
12178     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12179             if (bitVectBitValue(ic->rMask,i))
12180                     rsave = bitVectSetBit(rsave,i);
12181     }
12182     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12183                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12184     savermask(rsave);
12185
12186     to = parms[0];
12187     from = parms[1];
12188     count = parms[2];
12189
12190     aopOp (from, ic->next, FALSE, FALSE);
12191
12192     /* get from into DPTR1 */
12193     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12194     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12195     if (options.model == MODEL_FLAT24) {
12196         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12197     }
12198
12199     freeAsmop (from, NULL, ic, FALSE);
12200     aopOp (to, ic, FALSE, FALSE);
12201     /* get "to" into DPTR */
12202     /* if the operand is already in dptr
12203        then we do nothing else we move the value to dptr */
12204     if (AOP_TYPE (to) != AOP_STR) {
12205         /* if already in DPTR then we need to push */
12206         if (AOP_TYPE(to) == AOP_DPTR) {
12207             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12208             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12209             if (options.model == MODEL_FLAT24)
12210                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12211             emitcode ("pop", "dph");
12212             emitcode ("pop", "dpl");
12213         } else {
12214             _startLazyDPSEvaluation ();
12215             /* if this is remateriazable */
12216             if (AOP_TYPE (to) == AOP_IMMD) {
12217                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12218             } else {                    /* we need to get it byte by byte */
12219                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12220                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12221                 if (options.model == MODEL_FLAT24) {
12222                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12223                 }
12224             }
12225             _endLazyDPSEvaluation ();
12226         }
12227     }
12228     freeAsmop (to, NULL, ic, FALSE);
12229
12230     _G.dptrInUse = _G.dptr1InUse = 1;
12231     aopOp (count, ic->next->next, FALSE,FALSE);
12232     lbl =newiTempLabel(NULL);
12233
12234     /* now for the actual copy */
12235     if (AOP_TYPE(count) == AOP_LIT &&
12236         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12237         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12238         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12239         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12240         freeAsmop (count, NULL, ic, FALSE);
12241         emitcode ("","!tlabeldef",lbl->key+100);
12242         emitcode ("movx", "a,@dptr");   /* read data from port */
12243         emitcode ("dec","dps");         /* switch to DPTR */
12244         emitcode ("movx", "@dptr,a");   /* save into location */
12245         emitcode ("inc", "dptr");       /* point to next area */
12246         emitcode ("inc","dps");         /* switch to DPTR2 */
12247         emitcode ("djnz","b,!tlabel",lbl->key+100);
12248     } else {
12249         symbol *lbl1 = newiTempLabel(NULL);
12250
12251         emitcode (";"," Auto increment but no djnz");
12252         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12253         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12254         freeAsmop (count, NULL, ic, FALSE);
12255         emitcode ("mov", "dps,#!constbyte",0x1);        /* Select DPTR2 */
12256         emitcode ("","!tlabeldef",lbl->key+100);
12257         emitcode ("movx", "a,@dptr");
12258         emitcode ("dec","dps");         /* switch to DPTR */
12259         emitcode ("movx", "@dptr,a");
12260         emitcode ("inc", "dptr");
12261         emitcode ("inc","dps");         /* switch to DPTR2 */
12262 /*      emitcode ("djnz","b,!tlabel",lbl->key+100); */
12263 /*      emitcode ("djnz","_ap,!tlabel",lbl->key+100); */
12264         emitcode ("mov","a,b");
12265         emitcode ("orl","a,_ap");
12266         emitcode ("jz","!tlabel",lbl1->key+100);
12267         emitcode ("mov","a,_ap");
12268         emitcode ("add","a,#!constbyte",0xFF);
12269         emitcode ("mov","_ap,a");
12270         emitcode ("mov","a,b");
12271         emitcode ("addc","a,#!constbyte",0xFF);
12272         emitcode ("mov","b,a");
12273         emitcode ("sjmp","!tlabel",lbl->key+100);
12274         emitcode ("","!tlabeldef",lbl1->key+100);
12275     }
12276     emitcode ("mov", "dps,#0");
12277     _G.dptrInUse = _G.dptr1InUse = 0;
12278     unsavermask(rsave);
12279
12280 }
12281
12282 /*-----------------------------------------------------------------*/
12283 /* genOutp - gen code for __builtin_inp write data to a mem mapped */
12284 /* port, first parameter output area second parameter pointer to   */
12285 /* port third parameter count                                      */
12286 /*-----------------------------------------------------------------*/
12287 static void genOutp( iCode *ic, int nparms, operand **parms)
12288 {
12289     operand *from , *to , *count;
12290     symbol *lbl;
12291     bitVect *rsave;
12292     int i;
12293
12294     /* we know it has to be 3 parameters */
12295     assert (nparms == 3);
12296
12297     rsave = newBitVect(16);
12298     /* save DPTR if it needs to be saved */
12299     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12300             if (bitVectBitValue(ic->rMask,i))
12301                     rsave = bitVectSetBit(rsave,i);
12302     }
12303     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12304                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12305     savermask(rsave);
12306
12307     to = parms[0];
12308     from = parms[1];
12309     count = parms[2];
12310
12311     aopOp (from, ic->next, FALSE, FALSE);
12312
12313     /* get from into DPTR1 */
12314     emitcode ("mov", "dpl1,%s", aopGet (AOP (from), 0, FALSE, FALSE, NULL));
12315     emitcode ("mov", "dph1,%s", aopGet (AOP (from), 1, FALSE, FALSE, NULL));
12316     if (options.model == MODEL_FLAT24) {
12317         emitcode ("mov", "dpx1,%s", aopGet (AOP (from), 2, FALSE, FALSE, NULL));
12318     }
12319
12320     freeAsmop (from, NULL, ic, FALSE);
12321     aopOp (to, ic, FALSE, FALSE);
12322     /* get "to" into DPTR */
12323     /* if the operand is already in dptr
12324        then we do nothing else we move the value to dptr */
12325     if (AOP_TYPE (to) != AOP_STR) {
12326         /* if already in DPTR then we need to push */
12327         if (AOP_TYPE(to) == AOP_DPTR) {
12328             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12329             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12330             if (options.model == MODEL_FLAT24)
12331                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12332             emitcode ("pop", "dph");
12333             emitcode ("pop", "dpl");
12334         } else {
12335             _startLazyDPSEvaluation ();
12336             /* if this is remateriazable */
12337             if (AOP_TYPE (to) == AOP_IMMD) {
12338                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12339             } else {                    /* we need to get it byte by byte */
12340                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12341                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12342                 if (options.model == MODEL_FLAT24) {
12343                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12344                 }
12345             }
12346             _endLazyDPSEvaluation ();
12347         }
12348     }
12349     freeAsmop (to, NULL, ic, FALSE);
12350
12351     _G.dptrInUse = _G.dptr1InUse = 1;
12352     aopOp (count, ic->next->next, FALSE,FALSE);
12353     lbl =newiTempLabel(NULL);
12354
12355     /* now for the actual copy */
12356     if (AOP_TYPE(count) == AOP_LIT &&
12357         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12358         emitcode (";","OH  JOY auto increment with djnz (very fast)");
12359         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12360         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12361         emitcode ("","!tlabeldef",lbl->key+100);
12362         emitcode ("movx", "a,@dptr");   /* read data from port */
12363         emitcode ("inc","dps");         /* switch to DPTR2 */
12364         emitcode ("movx", "@dptr,a");   /* save into location */
12365         emitcode ("inc", "dptr");       /* point to next area */
12366         emitcode ("dec","dps");         /* switch to DPTR */
12367         emitcode ("djnz","b,!tlabel",lbl->key+100);
12368         freeAsmop (count, NULL, ic, FALSE);
12369     } else {
12370         symbol *lbl1 = newiTempLabel(NULL);
12371
12372         emitcode (";"," Auto increment but no djnz");
12373         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12374         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12375         freeAsmop (count, NULL, ic, FALSE);
12376         emitcode ("mov", "dps,#!constbyte",0x0);        /* Select DPTR */
12377         emitcode ("","!tlabeldef",lbl->key+100);
12378         emitcode ("movx", "a,@dptr");
12379         emitcode ("inc", "dptr");
12380         emitcode ("inc","dps");         /* switch to DPTR2 */
12381         emitcode ("movx", "@dptr,a");
12382         emitcode ("dec","dps");         /* switch to DPTR */
12383         emitcode ("mov","a,b");
12384         emitcode ("orl","a,_ap");
12385         emitcode ("jz","!tlabel",lbl1->key+100);
12386         emitcode ("mov","a,_ap");
12387         emitcode ("add","a,#!constbyte",0xFF);
12388         emitcode ("mov","_ap,a");
12389         emitcode ("mov","a,b");
12390         emitcode ("addc","a,#!constbyte",0xFF);
12391         emitcode ("mov","b,a");
12392         emitcode ("sjmp","!tlabel",lbl->key+100);
12393         emitcode ("","!tlabeldef",lbl1->key+100);
12394     }
12395     emitcode ("mov", "dps,#0");
12396     _G.dptrInUse = _G.dptr1InUse = 0;
12397     unsavermask(rsave);
12398
12399 }
12400
12401 /*-----------------------------------------------------------------*/
12402 /* genSwapW - swap lower & high order bytes                        */
12403 /*-----------------------------------------------------------------*/
12404 static void genSwapW(iCode *ic, int nparms, operand **parms)
12405 {
12406     operand *dest;
12407     operand *src;
12408     assert (nparms==1);
12409
12410     src = parms[0];
12411     dest=IC_RESULT(ic);
12412
12413     assert(getSize(operandType(src))==2);
12414
12415     aopOp (src, ic, FALSE, FALSE);
12416     emitcode ("mov","a,%s",aopGet(AOP(src),0,FALSE,FALSE,NULL));
12417     _G.accInUse++;
12418     MOVB(aopGet(AOP(src),1,FALSE,FALSE,"b"));
12419     _G.accInUse--;
12420     freeAsmop (src, NULL, ic, FALSE);
12421
12422     aopOp (dest,ic, FALSE, FALSE);
12423     aopPut(AOP(dest),"b",0);
12424     aopPut(AOP(dest),"a",1);
12425     freeAsmop (dest, NULL, ic, FALSE);
12426 }
12427
12428 /*-----------------------------------------------------------------*/
12429 /* genMemsetX - gencode for memSetX data                           */
12430 /*-----------------------------------------------------------------*/
12431 static void genMemsetX(iCode *ic, int nparms, operand **parms)
12432 {
12433     operand *to , *val , *count;
12434     symbol *lbl;
12435     char *l;
12436     int i;
12437     bitVect *rsave;
12438
12439     /* we know it has to be 3 parameters */
12440     assert (nparms == 3);
12441
12442     to = parms[0];
12443     val = parms[1];
12444     count = parms[2];
12445
12446     /* save DPTR if it needs to be saved */
12447     rsave = newBitVect(16);
12448     for (i = DPL_IDX ; i <= B_IDX ; i++ ) {
12449             if (bitVectBitValue(ic->rMask,i))
12450                     rsave = bitVectSetBit(rsave,i);
12451     }
12452     rsave = bitVectIntersect(rsave,bitVectCplAnd (bitVectCopy (ic->rMask),
12453                                                   ds390_rUmaskForOp (IC_RESULT(ic))));
12454     savermask(rsave);
12455
12456     aopOp (to, ic, FALSE, FALSE);
12457     /* get "to" into DPTR */
12458     /* if the operand is already in dptr
12459        then we do nothing else we move the value to dptr */
12460     if (AOP_TYPE (to) != AOP_STR) {
12461         /* if already in DPTR then we need to push */
12462         if (AOP_TYPE(to) == AOP_DPTR) {
12463             emitcode ("push", "%s", aopGet (AOP (to), 0, FALSE, TRUE, NULL));
12464             emitcode ("push", "%s", aopGet (AOP (to), 1, FALSE, TRUE, NULL));
12465             if (options.model == MODEL_FLAT24)
12466                 emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12467             emitcode ("pop", "dph");
12468             emitcode ("pop", "dpl");
12469         } else {
12470             _startLazyDPSEvaluation ();
12471             /* if this is remateriazable */
12472             if (AOP_TYPE (to) == AOP_IMMD) {
12473                 emitcode ("mov", "dptr,%s", aopGet (AOP (to), 0, TRUE, FALSE, NULL));
12474             } else {                    /* we need to get it byte by byte */
12475                 emitcode ("mov", "dpl,%s", aopGet (AOP (to), 0, FALSE, FALSE, NULL));
12476                 emitcode ("mov", "dph,%s", aopGet (AOP (to), 1, FALSE, FALSE, NULL));
12477                 if (options.model == MODEL_FLAT24) {
12478                     emitcode ("mov", "dpx,%s", aopGet (AOP (to), 2, FALSE, FALSE, NULL));
12479                 }
12480             }
12481             _endLazyDPSEvaluation ();
12482         }
12483     }
12484     freeAsmop (to, NULL, ic, FALSE);
12485
12486     aopOp (val, ic->next->next, FALSE,FALSE);
12487     aopOp (count, ic->next->next, FALSE,FALSE);
12488     lbl =newiTempLabel(NULL);
12489     /* now for the actual copy */
12490     if (AOP_TYPE(count) == AOP_LIT &&
12491         (int)floatFromVal (AOP(count)->aopu.aop_lit) <= 256) {
12492         l = aopGet(AOP (val), 0, FALSE, FALSE, NULL);
12493         emitcode ("mov", "b,%s",aopGet(AOP(count),0,FALSE,FALSE,NULL));
12494         MOVA(l);
12495         emitcode ("","!tlabeldef",lbl->key+100);
12496         emitcode ("movx", "@dptr,a");
12497         emitcode ("inc", "dptr");
12498         emitcode ("djnz","b,!tlabel",lbl->key+100);
12499     } else {
12500         symbol *lbl1 = newiTempLabel(NULL);
12501
12502         emitcode ("mov","_ap,%s",aopGet (AOP (count), 0, FALSE, TRUE, NULL));
12503         emitcode ("mov","b,%s",aopGet (AOP (count), 1, FALSE, TRUE, NULL));
12504         emitcode ("","!tlabeldef",lbl->key+100);
12505         MOVA (aopGet(AOP (val), 0, FALSE, FALSE, NULL));
12506         emitcode ("movx", "@dptr,a");
12507         emitcode ("inc", "dptr");
12508         emitcode ("mov","a,b");
12509         emitcode ("orl","a,_ap");
12510         emitcode ("jz","!tlabel",lbl1->key+100);
12511         emitcode ("mov","a,_ap");
12512         emitcode ("add","a,#!constbyte",0xFF);
12513         emitcode ("mov","_ap,a");
12514         emitcode ("mov","a,b");
12515         emitcode ("addc","a,#!constbyte",0xFF);
12516         emitcode ("mov","b,a");
12517         emitcode ("sjmp","!tlabel",lbl->key+100);
12518         emitcode ("","!tlabeldef",lbl1->key+100);
12519     }
12520     freeAsmop (count, NULL, ic, FALSE);
12521     unsavermask(rsave);
12522 }
12523
12524 /*-----------------------------------------------------------------*/
12525 /* genNatLibLoadPrimitive - calls TINI api function to load primitive */
12526 /*-----------------------------------------------------------------*/
12527 static void genNatLibLoadPrimitive(iCode *ic, int nparms, operand **parms,int size)
12528 {
12529         bitVect *rsave ;
12530         operand *pnum, *result;
12531         int i;
12532
12533         assert (nparms==1);
12534         /* save registers that need to be saved */
12535         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12536                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12537
12538         pnum = parms[0];
12539         aopOp (pnum, ic, FALSE, FALSE);
12540         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
12541         freeAsmop (pnum, NULL, ic, FALSE);
12542         emitcode ("lcall","NatLib_LoadPrimitive");
12543         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
12544         if (aopHasRegs(AOP(result),R0_IDX,R1_IDX) ||
12545             aopHasRegs(AOP(result),R2_IDX,R3_IDX) ) {
12546                 for (i = (size-1) ; i >= 0 ; i-- ) {
12547                         emitcode ("push","a%s",javaRet[i]);
12548                 }
12549                 for (i=0; i < size ; i++ ) {
12550                         emitcode ("pop","a%s",
12551                                   aopGet(AOP(result),i,FALSE,FALSE,DP2_RESULT_REG));
12552                 }
12553         } else {
12554                 for (i = 0 ; i < size ; i++ ) {
12555                         aopPut(AOP(result),javaRet[i],i);
12556                 }
12557         }
12558         freeAsmop (result, NULL, ic, FALSE);
12559         unsavermask(rsave);
12560 }
12561
12562 /*-----------------------------------------------------------------*/
12563 /* genNatLibLoadPointer - calls TINI api function to load pointer  */
12564 /*-----------------------------------------------------------------*/
12565 static void genNatLibLoadPointer(iCode *ic, int nparms, operand **parms)
12566 {
12567         bitVect *rsave ;
12568         operand *pnum, *result;
12569         int size = 3;
12570         int i;
12571
12572         assert (nparms==1);
12573         /* save registers that need to be saved */
12574         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12575                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12576
12577         pnum = parms[0];
12578         aopOp (pnum, ic, FALSE, FALSE);
12579         emitcode ("mov","a,%s",aopGet(AOP(pnum),0,FALSE,FALSE,DP2_RESULT_REG));
12580         freeAsmop (pnum, NULL, ic, FALSE);
12581         emitcode ("lcall","NatLib_LoadPointer");
12582         aopOp (result=IC_RESULT(ic), ic, FALSE, FALSE);
12583         if (AOP_TYPE(result)!=AOP_STR) {
12584                 for (i = 0 ; i < size ; i++ ) {
12585                         aopPut(AOP(result),fReturn[i],i);
12586                 }
12587         }
12588         freeAsmop (result, NULL, ic, FALSE);
12589         unsavermask(rsave);
12590 }
12591
12592 /*-----------------------------------------------------------------*/
12593 /* genNatLibInstallStateBlock -                                    */
12594 /*-----------------------------------------------------------------*/
12595 static void genNatLibInstallStateBlock(iCode *ic, int nparms,
12596                                        operand **parms, const char *name)
12597 {
12598         bitVect *rsave ;
12599         operand *psb, *handle;
12600         assert (nparms==2);
12601
12602         /* save registers that need to be saved */
12603         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12604                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12605         psb = parms[0];
12606         handle = parms[1];
12607
12608         /* put pointer to state block into DPTR1 */
12609         aopOp (psb, ic, FALSE, FALSE);
12610         if (AOP_TYPE (psb) == AOP_IMMD) {
12611                 emitcode ("mov","dps,#1");
12612                 emitcode ("mov", "dptr,%s",
12613                           aopGet (AOP (psb), 0, TRUE, FALSE, DP2_RESULT_REG));
12614                 emitcode ("mov","dps,#0");
12615         } else {
12616                 emitcode ("mov","dpl1,%s",aopGet(AOP(psb),0,FALSE,FALSE,DP2_RESULT_REG));
12617                 emitcode ("mov","dph1,%s",aopGet(AOP(psb),1,FALSE,FALSE,DP2_RESULT_REG));
12618                 emitcode ("mov","dpx1,%s",aopGet(AOP(psb),2,FALSE,FALSE,DP2_RESULT_REG));
12619         }
12620         freeAsmop (psb, NULL, ic, FALSE);
12621
12622         /* put libraryID into DPTR */
12623         emitcode ("mov","dptr,#LibraryID");
12624
12625         /* put handle into r3:r2 */
12626         aopOp (handle, ic, FALSE, FALSE);
12627         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12628                 emitcode ("push","%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12629                 emitcode ("push","%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12630                 emitcode ("pop","ar3");
12631                 emitcode ("pop","ar2");
12632         } else {
12633                 emitcode ("mov","r2,%s",aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12634                 emitcode ("mov","r3,%s",aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12635         }
12636         freeAsmop (psb, NULL, ic, FALSE);
12637
12638         /* make the call */
12639         emitcode ("lcall","NatLib_Install%sStateBlock",name);
12640
12641         /* put return value into place*/
12642         _G.accInUse++;
12643         aopOp (IC_RESULT(ic), ic, FALSE, FALSE);
12644         _G.accInUse--;
12645         aopPut(AOP(IC_RESULT(ic)),"a",0);
12646         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12647         unsavermask(rsave);
12648 }
12649
12650 /*-----------------------------------------------------------------*/
12651 /* genNatLibRemoveStateBlock -                                     */
12652 /*-----------------------------------------------------------------*/
12653 static void genNatLibRemoveStateBlock(iCode *ic,int nparms,const char *name)
12654 {
12655         bitVect *rsave ;
12656
12657         assert(nparms==0);
12658
12659         /* save registers that need to be saved */
12660         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12661                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12662
12663         /* put libraryID into DPTR */
12664         emitcode ("mov","dptr,#LibraryID");
12665         /* make the call */
12666         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12667         unsavermask(rsave);
12668 }
12669
12670 /*-----------------------------------------------------------------*/
12671 /* genNatLibGetStateBlock -                                        */
12672 /*-----------------------------------------------------------------*/
12673 static void genNatLibGetStateBlock(iCode *ic,int nparms,
12674                                    operand **parms,const char *name)
12675 {
12676         bitVect *rsave ;
12677         symbol *lbl = newiTempLabel(NULL);
12678
12679         assert(nparms==0);
12680         /* save registers that need to be saved */
12681         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12682                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12683
12684         /* put libraryID into DPTR */
12685         emitcode ("mov","dptr,#LibraryID");
12686         /* make the call */
12687         emitcode ("lcall","NatLib_Remove%sStateBlock",name);
12688         emitcode ("jnz","!tlabel",lbl->key+100);
12689
12690         /* put return value into place */
12691         aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12692         if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12693                 emitcode ("push","ar3");
12694                 emitcode ("push","ar2");
12695                 emitcode ("pop","%s",
12696                           aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12697                 emitcode ("pop","%s",
12698                           aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12699         } else {
12700                 aopPut(AOP(IC_RESULT(ic)),"r2",0);
12701                 aopPut(AOP(IC_RESULT(ic)),"r3",1);
12702         }
12703         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12704         emitcode ("","!tlabeldef",lbl->key+100);
12705         unsavermask(rsave);
12706 }
12707
12708 /*-----------------------------------------------------------------*/
12709 /* genMMMalloc -                                                   */
12710 /*-----------------------------------------------------------------*/
12711 static void genMMMalloc (iCode *ic,int nparms, operand **parms,
12712                          int size, const char *name)
12713 {
12714         bitVect *rsave ;
12715         operand *bsize;
12716         symbol *rsym;
12717         symbol *lbl = newiTempLabel(NULL);
12718
12719         assert (nparms == 1);
12720         /* save registers that need to be saved */
12721         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12722                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12723
12724         bsize=parms[0];
12725         aopOp (bsize,ic,FALSE,FALSE);
12726
12727         /* put the size in R4-R2 */
12728         if (aopHasRegs(AOP(bsize),R2_IDX, (size==3 ? R4_IDX: R3_IDX))) {
12729                 emitcode("push","%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12730                 emitcode("push","%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12731                 if (size==3) {
12732                         emitcode("push","%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12733                         emitcode("pop","ar4");
12734                 }
12735                 emitcode("pop","ar3");
12736                 emitcode("pop","ar2");
12737         } else {
12738                 emitcode ("mov","r2,%s",aopGet(AOP(bsize),0,FALSE,TRUE,DP2_RESULT_REG));
12739                 emitcode ("mov","r3,%s",aopGet(AOP(bsize),1,FALSE,TRUE,DP2_RESULT_REG));
12740                 if (size==3) {
12741                         emitcode("mov","r4,%s",aopGet(AOP(bsize),2,FALSE,TRUE,DP2_RESULT_REG));
12742                 }
12743         }
12744         freeAsmop (bsize, NULL, ic, FALSE);
12745
12746         /* make the call */
12747         emitcode ("lcall","MM_%s",name);
12748         emitcode ("jz","!tlabel",lbl->key+100);
12749         emitcode ("mov","r2,#!constbyte",0xff);
12750         emitcode ("mov","r3,#!constbyte",0xff);
12751         emitcode ("","!tlabeldef",lbl->key+100);
12752         /* we don't care about the pointer : we just save the handle */
12753         rsym = OP_SYMBOL(IC_RESULT(ic));
12754         if (rsym->liveFrom != rsym->liveTo) {
12755                 aopOp(IC_RESULT(ic),ic,FALSE,FALSE);
12756                 if (aopHasRegs(AOP(IC_RESULT(ic)),R2_IDX,R3_IDX)) {
12757                         emitcode ("push","ar3");
12758                         emitcode ("push","ar2");
12759                         emitcode ("pop","%s",
12760                                   aopGet(AOP(IC_RESULT(ic)),0,FALSE,TRUE,DP2_RESULT_REG));
12761                         emitcode ("pop","%s",
12762                                   aopGet(AOP(IC_RESULT(ic)),1,FALSE,TRUE,DP2_RESULT_REG));
12763                 } else {
12764                         aopPut(AOP(IC_RESULT(ic)),"r2",0);
12765                         aopPut(AOP(IC_RESULT(ic)),"r3",1);
12766                 }
12767                 freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12768         }
12769         unsavermask(rsave);
12770 }
12771
12772 /*-----------------------------------------------------------------*/
12773 /* genMMDeref -                                                    */
12774 /*-----------------------------------------------------------------*/
12775 static void genMMDeref (iCode *ic,int nparms, operand **parms)
12776 {
12777         bitVect *rsave ;
12778         operand *handle;
12779
12780         assert (nparms == 1);
12781         /* save registers that need to be saved */
12782         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12783                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12784
12785         handle=parms[0];
12786         aopOp (handle,ic,FALSE,FALSE);
12787
12788         /* put the size in R4-R2 */
12789         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12790                 emitcode("push","%s",
12791                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12792                 emitcode("push","%s",
12793                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12794                 emitcode("pop","ar3");
12795                 emitcode("pop","ar2");
12796         } else {
12797                 emitcode ("mov","r2,%s",
12798                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12799                 emitcode ("mov","r3,%s",
12800                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12801         }
12802         freeAsmop (handle, NULL, ic, FALSE);
12803
12804         /* make the call */
12805         emitcode ("lcall","MM_Deref");
12806
12807         {
12808                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12809                 if (rsym->liveFrom != rsym->liveTo) {
12810                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12811                         if (AOP_TYPE(IC_RESULT(ic)) != AOP_STR) {
12812                             _startLazyDPSEvaluation ();
12813
12814                                 aopPut(AOP(IC_RESULT(ic)),"dpl",0);
12815                                 aopPut(AOP(IC_RESULT(ic)),"dph",1);
12816                                 aopPut(AOP(IC_RESULT(ic)),"dpx",2);
12817
12818                             _endLazyDPSEvaluation ();
12819
12820                         }
12821                 }
12822         }
12823         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12824         unsavermask(rsave);
12825 }
12826
12827 /*-----------------------------------------------------------------*/
12828 /* genMMUnrestrictedPersist -                                      */
12829 /*-----------------------------------------------------------------*/
12830 static void genMMUnrestrictedPersist(iCode *ic,int nparms, operand **parms)
12831 {
12832         bitVect *rsave ;
12833         operand *handle;
12834
12835         assert (nparms == 1);
12836         /* save registers that need to be saved */
12837         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12838                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12839
12840         handle=parms[0];
12841         aopOp (handle,ic,FALSE,FALSE);
12842
12843         /* put the size in R3-R2 */
12844         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12845                 emitcode("push","%s",
12846                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12847                 emitcode("push","%s",
12848                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12849                 emitcode("pop","ar3");
12850                 emitcode("pop","ar2");
12851         } else {
12852                 emitcode ("mov","r2,%s",
12853                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12854                 emitcode ("mov","r3,%s",
12855                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12856         }
12857         freeAsmop (handle, NULL, ic, FALSE);
12858
12859         /* make the call */
12860         emitcode ("lcall","MM_UnrestrictedPersist");
12861
12862         {
12863                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12864                 if (rsym->liveFrom != rsym->liveTo) {
12865                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12866                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12867                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12868                 }
12869         }
12870         unsavermask(rsave);
12871 }
12872
12873 /*-----------------------------------------------------------------*/
12874 /* genSystemExecJavaProcess -                                      */
12875 /*-----------------------------------------------------------------*/
12876 static void genSystemExecJavaProcess(iCode *ic,int nparms, operand **parms)
12877 {
12878         bitVect *rsave ;
12879         operand *handle, *pp;
12880
12881         assert (nparms==2);
12882         /* save registers that need to be saved */
12883         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12884                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12885
12886         pp = parms[0];
12887         handle = parms[1];
12888
12889         /* put the handle in R3-R2 */
12890         aopOp (handle,ic,FALSE,FALSE);
12891         if (aopHasRegs(AOP(handle),R2_IDX,R3_IDX)) {
12892                 emitcode("push","%s",
12893                          aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12894                 emitcode("push","%s",
12895                          aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12896                 emitcode("pop","ar3");
12897                 emitcode("pop","ar2");
12898         } else {
12899                 emitcode ("mov","r2,%s",
12900                           aopGet(AOP(handle),0,FALSE,TRUE,DP2_RESULT_REG));
12901                 emitcode ("mov","r3,%s",
12902                           aopGet(AOP(handle),1,FALSE,TRUE,DP2_RESULT_REG));
12903         }
12904         freeAsmop (handle, NULL, ic, FALSE);
12905
12906         /* put pointer in DPTR */
12907         aopOp (pp,ic,FALSE,FALSE);
12908         if (AOP_TYPE(pp) == AOP_IMMD) {
12909                 emitcode ("mov", "dptr,%s",
12910                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12911         } else if (AOP_TYPE(pp) != AOP_STR) { /* not already in dptr */
12912                 emitcode ("mov","dpl,%s",aopGet(AOP(pp),0,FALSE,FALSE,NULL));
12913                 emitcode ("mov","dph,%s",aopGet(AOP(pp),1,FALSE,FALSE,NULL));
12914                 emitcode ("mov","dpx,%s",aopGet(AOP(pp),2,FALSE,FALSE,NULL));
12915         }
12916         freeAsmop (handle, NULL, ic, FALSE);
12917
12918         /* make the call */
12919         emitcode ("lcall","System_ExecJavaProcess");
12920
12921         /* put result in place */
12922         {
12923                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
12924                 if (rsym->liveFrom != rsym->liveTo) {
12925                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
12926                         aopPut(AOP(IC_RESULT(ic)),"a",0);
12927                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
12928                 }
12929         }
12930
12931         unsavermask(rsave);
12932 }
12933
12934 /*-----------------------------------------------------------------*/
12935 /* genSystemRTCRegisters -                                         */
12936 /*-----------------------------------------------------------------*/
12937 static void genSystemRTCRegisters(iCode *ic,int nparms, operand **parms,
12938                                   char *name)
12939 {
12940         bitVect *rsave ;
12941         operand *pp;
12942
12943         assert (nparms==1);
12944         /* save registers that need to be saved */
12945         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12946                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12947
12948         pp=parms[0];
12949         /* put pointer in DPTR */
12950         aopOp (pp,ic,FALSE,FALSE);
12951         if (AOP_TYPE (pp) == AOP_IMMD) {
12952                 emitcode ("mov","dps,#1");
12953                 emitcode ("mov", "dptr,%s",
12954                           aopGet (AOP (pp), 0, TRUE, FALSE, NULL));
12955                 emitcode ("mov","dps,#0");
12956         } else {
12957                 emitcode ("mov","dpl1,%s",
12958                           aopGet(AOP(pp),0,FALSE,FALSE,DP2_RESULT_REG));
12959                 emitcode ("mov","dph1,%s",
12960                           aopGet(AOP(pp),1,FALSE,FALSE,DP2_RESULT_REG));
12961                 emitcode ("mov","dpx1,%s",
12962                           aopGet(AOP(pp),2,FALSE,FALSE,DP2_RESULT_REG));
12963         }
12964         freeAsmop (pp, NULL, ic, FALSE);
12965
12966         /* make the call */
12967         emitcode ("lcall","System_%sRTCRegisters",name);
12968
12969         unsavermask(rsave);
12970 }
12971
12972 /*-----------------------------------------------------------------*/
12973 /* genSystemThreadSleep -                                          */
12974 /*-----------------------------------------------------------------*/
12975 static void genSystemThreadSleep(iCode *ic,int nparms, operand **parms, char *name)
12976 {
12977         bitVect *rsave ;
12978         operand *to, *s;
12979
12980         assert (nparms==1);
12981         /* save registers that need to be saved */
12982         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
12983                                          ds390_rUmaskForOp (IC_RESULT(ic))));
12984
12985         to = parms[0];
12986         aopOp(to,ic,FALSE,FALSE);
12987         if (aopHasRegs(AOP(to),R2_IDX,R3_IDX) ||
12988             aopHasRegs(AOP(to),R0_IDX,R1_IDX) ) {
12989                 emitcode ("push","%s",
12990                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
12991                 emitcode ("push","%s",
12992                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
12993                 emitcode ("push","%s",
12994                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
12995                 emitcode ("push","%s",
12996                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
12997                 emitcode ("pop","ar3");
12998                 emitcode ("pop","ar2");
12999                 emitcode ("pop","ar1");
13000                 emitcode ("pop","ar0");
13001         } else {
13002                 emitcode ("mov","r0,%s",
13003                           aopGet(AOP(to),0,FALSE,TRUE,DP2_RESULT_REG));
13004                 emitcode ("mov","r1,%s",
13005                           aopGet(AOP(to),1,FALSE,TRUE,DP2_RESULT_REG));
13006                 emitcode ("mov","r2,%s",
13007                           aopGet(AOP(to),2,FALSE,TRUE,DP2_RESULT_REG));
13008                 emitcode ("mov","r3,%s",
13009                           aopGet(AOP(to),3,FALSE,TRUE,DP2_RESULT_REG));
13010         }
13011         freeAsmop (to, NULL, ic, FALSE);
13012
13013         /* suspend in acc */
13014         s = parms[1];
13015         aopOp(s,ic,FALSE,FALSE);
13016         emitcode ("mov","a,%s",
13017                   aopGet(AOP(s),0,FALSE,TRUE,NULL));
13018         freeAsmop (s, NULL, ic, FALSE);
13019
13020         /* make the call */
13021         emitcode ("lcall","System_%s",name);
13022
13023         unsavermask(rsave);
13024 }
13025
13026 /*-----------------------------------------------------------------*/
13027 /* genSystemThreadResume -                                         */
13028 /*-----------------------------------------------------------------*/
13029 static void genSystemThreadResume(iCode *ic,int nparms, operand **parms)
13030 {
13031         bitVect *rsave ;
13032         operand *tid,*pid;
13033
13034         assert (nparms==2);
13035         /* save registers that need to be saved */
13036         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13037                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13038
13039         tid = parms[0];
13040         pid = parms[1];
13041
13042         /* PID in R0 */
13043         aopOp(pid,ic,FALSE,FALSE);
13044         emitcode ("mov","r0,%s",
13045                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
13046         freeAsmop (pid, NULL, ic, FALSE);
13047
13048         /* tid into ACC */
13049         aopOp(tid,ic,FALSE,FALSE);
13050         emitcode ("mov","a,%s",
13051                   aopGet(AOP(tid),0,FALSE,TRUE,DP2_RESULT_REG));
13052         freeAsmop (tid, NULL, ic, FALSE);
13053
13054         emitcode ("lcall","System_ThreadResume");
13055
13056         /* put result into place */
13057         {
13058                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13059                 if (rsym->liveFrom != rsym->liveTo) {
13060                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13061                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13062                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13063                 }
13064         }
13065         unsavermask(rsave);
13066 }
13067
13068 /*-----------------------------------------------------------------*/
13069 /* genSystemProcessResume -                                        */
13070 /*-----------------------------------------------------------------*/
13071 static void genSystemProcessResume(iCode *ic,int nparms, operand **parms)
13072 {
13073         bitVect *rsave ;
13074         operand *pid;
13075
13076         assert (nparms==1);
13077         /* save registers that need to be saved */
13078         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13079                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13080
13081         pid = parms[0];
13082
13083         /* pid into ACC */
13084         aopOp(pid,ic,FALSE,FALSE);
13085         emitcode ("mov","a,%s",
13086                   aopGet(AOP(pid),0,FALSE,TRUE,DP2_RESULT_REG));
13087         freeAsmop (pid, NULL, ic, FALSE);
13088
13089         emitcode ("lcall","System_ProcessResume");
13090
13091         unsavermask(rsave);
13092 }
13093
13094 /*-----------------------------------------------------------------*/
13095 /* genSystem -                                                     */
13096 /*-----------------------------------------------------------------*/
13097 static void genSystem (iCode *ic,int nparms,char *name)
13098 {
13099         assert(nparms == 0);
13100
13101         emitcode ("lcall","System_%s",name);
13102 }
13103
13104 /*-----------------------------------------------------------------*/
13105 /* genSystemPoll -                                                  */
13106 /*-----------------------------------------------------------------*/
13107 static void genSystemPoll(iCode *ic,int nparms, operand **parms,char *name)
13108 {
13109         bitVect *rsave ;
13110         operand *fp;
13111
13112         assert (nparms==1);
13113         /* save registers that need to be saved */
13114         savermask(rsave = bitVectCplAnd (bitVectCopy (ic->rMask),
13115                                          ds390_rUmaskForOp (IC_RESULT(ic))));
13116
13117         fp = parms[0];
13118         aopOp (fp,ic,FALSE,FALSE);
13119         if (AOP_TYPE (fp) == AOP_IMMD) {
13120                 emitcode ("mov", "dptr,%s",
13121                           aopGet (AOP (fp), 0, TRUE, FALSE, DP2_RESULT_REG));
13122         } else if (AOP_TYPE(fp) != AOP_STR) { /* not already in dptr */
13123                 emitcode ("mov","dpl,%s",
13124                           aopGet(AOP(fp),0,FALSE,FALSE,DP2_RESULT_REG));
13125                 emitcode ("mov","dph,%s",
13126                           aopGet(AOP(fp),1,FALSE,FALSE,DP2_RESULT_REG));
13127                 emitcode ("mov","dpx,%s",
13128                           aopGet(AOP(fp),2,FALSE,FALSE,DP2_RESULT_REG));
13129         }
13130         freeAsmop (fp, NULL, ic, FALSE);
13131
13132         emitcode ("lcall","System_%sPoll",name);
13133
13134         /* put result into place */
13135         {
13136                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13137                 if (rsym->liveFrom != rsym->liveTo) {
13138                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13139                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13140                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13141                 }
13142         }
13143         unsavermask(rsave);
13144 }
13145
13146 /*-----------------------------------------------------------------*/
13147 /* genSystemGetCurrentID -                                         */
13148 /*-----------------------------------------------------------------*/
13149 static void genSystemGetCurrentID(iCode *ic,int nparms, operand **parms,char *name)
13150 {
13151         assert (nparms==0);
13152
13153         emitcode ("lcall","System_GetCurrent%sId",name);
13154         /* put result into place */
13155         {
13156                 symbol *rsym = OP_SYMBOL(IC_RESULT(ic));
13157                 if (rsym->liveFrom != rsym->liveTo) {
13158                         aopOp (IC_RESULT(ic),ic,FALSE,FALSE);
13159                         aopPut(AOP(IC_RESULT(ic)),"a",0);
13160                         freeAsmop (IC_RESULT(ic), NULL, ic, FALSE);
13161                 }
13162         }
13163 }
13164
13165 /*-----------------------------------------------------------------*/
13166 /* genDummyRead - generate code for dummy read of volatiles        */
13167 /*-----------------------------------------------------------------*/
13168 static void
13169 genDummyRead (iCode * ic)
13170 {
13171   operand *op;
13172   int size, offset;
13173
13174   D(emitcode(";     genDummyRead",""));
13175
13176   op = IC_RIGHT (ic);
13177   if (op && IS_SYMOP (op))
13178     {
13179       aopOp (op, ic, FALSE, FALSE);
13180
13181       /* if the result is a bit */
13182       if (AOP_TYPE (op) == AOP_CRY)
13183         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13184       else
13185         {
13186           /* bit variables done */
13187           /* general case */
13188           size = AOP_SIZE (op);
13189           offset = 0;
13190           while (size--)
13191           {
13192             MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
13193             offset++;
13194           }
13195         }
13196
13197       freeAsmop (op, NULL, ic, TRUE);
13198     }
13199
13200   op = IC_LEFT (ic);
13201   if (op && IS_SYMOP (op))
13202     {
13203       aopOp (op, ic, FALSE, FALSE);
13204
13205       /* if the result is a bit */
13206       if (AOP_TYPE (op) == AOP_CRY)
13207         emitcode ("mov", "c,%s", AOP (op)->aopu.aop_dir);
13208       else
13209         {
13210           /* bit variables done */
13211           /* general case */
13212           size = AOP_SIZE (op);
13213           offset = 0;
13214           while (size--)
13215           {
13216             MOVA (aopGet (AOP (op), offset, FALSE, FALSE, FALSE));
13217             offset++;
13218           }
13219         }
13220
13221       freeAsmop (op, NULL, ic, TRUE);
13222     }
13223
13224 }
13225
13226 /*-----------------------------------------------------------------*/
13227 /* genCritical - generate code for start of a critical sequence    */
13228 /*-----------------------------------------------------------------*/
13229 static void
13230 genCritical (iCode *ic)
13231 {
13232   symbol *tlbl = newiTempLabel (NULL);
13233
13234   D(emitcode(";     genCritical",""));
13235
13236   if (IC_RESULT (ic))
13237     aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
13238
13239   emitcode ("setb", "c");
13240   emitcode ("jbc", "ea,%05d$", (tlbl->key + 100)); /* atomic test & clear */
13241   emitcode ("clr", "c");
13242   emitcode ("", "%05d$:", (tlbl->key + 100));
13243
13244   if (IC_RESULT (ic))
13245     outBitC (IC_RESULT (ic)); /* save old ea in an operand */
13246   else
13247     emitcode ("push", "psw"); /* save old ea via c in psw on top of stack*/
13248
13249   if (IC_RESULT (ic))
13250     freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
13251 }
13252
13253 /*-----------------------------------------------------------------*/
13254 /* genEndCritical - generate code for end of a critical sequence   */
13255 /*-----------------------------------------------------------------*/
13256 static void
13257 genEndCritical (iCode *ic)
13258 {
13259   D(emitcode(";     genEndCritical",""));
13260
13261   if (IC_RIGHT (ic))
13262     {
13263       aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
13264       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
13265         {
13266           emitcode ("mov", "c,%s", IC_RIGHT (ic)->aop->aopu.aop_dir);
13267           emitcode ("mov", "ea,c");
13268         }
13269       else
13270         {
13271           MOVA (aopGet (AOP (IC_RIGHT (ic)), 0, FALSE, FALSE, FALSE));
13272           emitcode ("rrc", "a");
13273           emitcode ("mov", "ea,c");
13274         }
13275       freeAsmop (IC_RIGHT (ic), NULL, ic, TRUE);
13276     }
13277   else
13278     {
13279       emitcode ("pop", "psw"); /* restore ea via c in psw on top of stack */
13280       emitcode ("mov", "ea,c");
13281     }
13282 }
13283
13284
13285
13286 /*-----------------------------------------------------------------*/
13287 /* genBuiltIn - calls the appropriate function to  generating code */
13288 /* for a built in function                                         */
13289 /*-----------------------------------------------------------------*/
13290 static void genBuiltIn (iCode *ic)
13291 {
13292         operand *bi_parms[MAX_BUILTIN_ARGS];
13293         int nbi_parms;
13294         iCode *bi_iCode;
13295         symbol *bif;
13296
13297         /* get all the arguments for a built in function */
13298         bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
13299
13300         /* which function is it */
13301         bif = OP_SYMBOL(IC_LEFT(bi_iCode));
13302         if (strcmp(bif->name,"__builtin_memcpy_x2x")==0) {
13303                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,0);
13304         } else if (strcmp(bif->name,"__builtin_memcpy_c2x")==0) {
13305                 genMemcpyX2X(bi_iCode,nbi_parms,bi_parms,1);
13306         } else  if (strcmp(bif->name,"__builtin_memcmp_x2x")==0) {
13307                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,0);
13308         } else if (strcmp(bif->name,"__builtin_memcmp_c2x")==0) {
13309                 genMemcmpX2X(bi_iCode,nbi_parms,bi_parms,1);
13310         } else if (strcmp(bif->name,"__builtin_memset_x")==0) {
13311                 genMemsetX(bi_iCode,nbi_parms,bi_parms);
13312         } else if (strcmp(bif->name,"__builtin_inp")==0) {
13313                 genInp(bi_iCode,nbi_parms,bi_parms);
13314         } else if (strcmp(bif->name,"__builtin_outp")==0) {
13315                 genOutp(bi_iCode,nbi_parms,bi_parms);
13316         } else if (strcmp(bif->name,"__builtin_swapw")==0) {
13317                 genSwapW(bi_iCode,nbi_parms,bi_parms);
13318                 /* JavaNative builtIns */
13319         } else if (strcmp(bif->name,"NatLib_LoadByte")==0) {
13320                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,1);
13321         } else if (strcmp(bif->name,"NatLib_LoadShort")==0) {
13322                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,2);
13323         } else if (strcmp(bif->name,"NatLib_LoadInt")==0) {
13324                 genNatLibLoadPrimitive(bi_iCode,nbi_parms,bi_parms,4);
13325         } else if (strcmp(bif->name,"NatLib_LoadPointer")==0) {
13326                 genNatLibLoadPointer(bi_iCode,nbi_parms,bi_parms);
13327         } else if (strcmp(bif->name,"NatLib_InstallImmutableStateBlock")==0) {
13328                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13329         } else if (strcmp(bif->name,"NatLib_InstallEphemeralStateBlock")==0) {
13330                 genNatLibInstallStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13331         } else if (strcmp(bif->name,"NatLib_RemoveImmutableStateBlock")==0) {
13332                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Immutable");
13333         } else if (strcmp(bif->name,"NatLib_RemoveEphemeralStateBlock")==0) {
13334                 genNatLibRemoveStateBlock(bi_iCode,nbi_parms,"Ephemeral");
13335         } else if (strcmp(bif->name,"NatLib_GetImmutableStateBlock")==0) {
13336                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Immutable");
13337         } else if (strcmp(bif->name,"NatLib_GetEphemeralStateBlock")==0) {
13338                 genNatLibGetStateBlock(bi_iCode,nbi_parms,bi_parms,"Ephemeral");
13339         } else if (strcmp(bif->name,"MM_XMalloc")==0) {
13340                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,3,"XMalloc");
13341         } else if (strcmp(bif->name,"MM_Malloc")==0) {
13342                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Malloc");
13343         } else if (strcmp(bif->name,"MM_ApplicationMalloc")==0) {
13344                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"ApplicationMalloc");
13345         } else if (strcmp(bif->name,"MM_Free")==0) {
13346                 genMMMalloc(bi_iCode,nbi_parms,bi_parms,2,"Free");
13347         } else if (strcmp(bif->name,"MM_Deref")==0) {
13348                 genMMDeref(bi_iCode,nbi_parms,bi_parms);
13349         } else if (strcmp(bif->name,"MM_UnrestrictedPersist")==0) {
13350                 genMMUnrestrictedPersist(bi_iCode,nbi_parms,bi_parms);
13351         } else if (strcmp(bif->name,"System_ExecJavaProcess")==0) {
13352                 genSystemExecJavaProcess(bi_iCode,nbi_parms,bi_parms);
13353         } else if (strcmp(bif->name,"System_GetRTCRegisters")==0) {
13354                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Get");
13355         } else if (strcmp(bif->name,"System_SetRTCRegisters")==0) {
13356                 genSystemRTCRegisters(bi_iCode,nbi_parms,bi_parms,"Set");
13357         } else if (strcmp(bif->name,"System_ThreadSleep")==0) {
13358                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep");
13359         } else if (strcmp(bif->name,"System_ThreadSleep_ExitCriticalSection")==0) {
13360                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ThreadSleep_ExitCriticalSection");
13361         } else if (strcmp(bif->name,"System_ProcessSleep")==0) {
13362                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep");
13363         } else if (strcmp(bif->name,"System_ProcessSleep_ExitCriticalSection")==0) {
13364                 genSystemThreadSleep(bi_iCode,nbi_parms,bi_parms,"ProcessSleep_ExitCriticalSection");
13365         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13366                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13367         } else if (strcmp(bif->name,"System_SaveThread")==0) {
13368                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13369         } else if (strcmp(bif->name,"System_ThreadResume")==0) {
13370                 genSystemThreadResume(bi_iCode,nbi_parms,bi_parms);
13371         } else if (strcmp(bif->name,"System_ProcessResume")==0) {
13372                 genSystemProcessResume(bi_iCode,nbi_parms,bi_parms);
13373         } else if (strcmp(bif->name,"System_SaveJavaThreadState")==0) {
13374                 genSystem(bi_iCode,nbi_parms,"SaveJavaThreadState");
13375         } else if (strcmp(bif->name,"System_RestoreJavaThreadState")==0) {
13376                 genSystem(bi_iCode,nbi_parms,"RestoreJavaThreadState");
13377         } else if (strcmp(bif->name,"System_ProcessYield")==0) {
13378                 genSystem(bi_iCode,nbi_parms,"ProcessYield");
13379         } else if (strcmp(bif->name,"System_ProcessSuspend")==0) {
13380                 genSystem(bi_iCode,nbi_parms,"ProcessSuspend");
13381         } else if (strcmp(bif->name,"System_RegisterPoll")==0) {
13382                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Register");
13383         } else if (strcmp(bif->name,"System_RemovePoll")==0) {
13384                 genSystemPoll(bi_iCode,nbi_parms,bi_parms,"Remove");
13385         } else if (strcmp(bif->name,"System_GetCurrentThreadId")==0) {
13386                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Thread");
13387         } else if (strcmp(bif->name,"System_GetCurrentProcessId")==0) {
13388                 genSystemGetCurrentID(bi_iCode,nbi_parms,bi_parms,"Process");
13389         } else {
13390                 werror(E_INTERNAL_ERROR,__FILE__,__LINE__,"unknown builtin function encountered\n");
13391                 return ;
13392         }
13393         return ;
13394 }
13395
13396 /*-----------------------------------------------------------------*/
13397 /* gen390Code - generate code for Dallas 390 based controllers     */
13398 /*-----------------------------------------------------------------*/
13399 void
13400 gen390Code (iCode * lic)
13401 {
13402   iCode *ic;
13403   int cln = 0;
13404
13405   lineHead = lineCurr = NULL;
13406   dptrn[1][0] = "dpl1";
13407   dptrn[1][1] = "dph1";
13408   dptrn[1][2] = "dpx1";
13409
13410   if (options.model == MODEL_FLAT24) {
13411     fReturnSizeDS390 = 5;
13412     fReturn = fReturn24;
13413   } else {
13414     fReturnSizeDS390 = 4;
13415     fReturn = fReturn16;
13416     options.stack10bit=0;
13417   }
13418 #if 1
13419   /* print the allocation information */
13420   if (allocInfo && currFunc)
13421     printAllocInfo (currFunc, codeOutFile);
13422 #endif
13423   /* if debug information required */
13424   if (options.debug && currFunc)
13425     {
13426       debugFile->writeFunction (currFunc, lic);
13427     }
13428   /* stack pointer name */
13429   if (options.useXstack)
13430     spname = "_spx";
13431   else
13432     spname = "sp";
13433
13434
13435   for (ic = lic; ic; ic = ic->next)
13436     {
13437       _G.current_iCode = ic;
13438
13439       if (ic->lineno && cln != ic->lineno)
13440         {
13441           if (options.debug)
13442             {
13443               debugFile->writeCLine (ic);
13444             }
13445           if (!options.noCcodeInAsm) {
13446             emitcode ("", ";\t%s:%d: %s", ic->filename, ic->lineno,
13447                       printCLine(ic->filename, ic->lineno));
13448           }
13449           cln = ic->lineno;
13450         }
13451       if (options.iCodeInAsm) {
13452         emitcode("", ";ic:%d: %s", ic->key, printILine(ic));
13453       }
13454       /* if the result is marked as
13455          spilt and rematerializable or code for
13456          this has already been generated then
13457          do nothing */
13458       if (resultRemat (ic) || ic->generated)
13459         continue;
13460
13461       /* depending on the operation */
13462       switch (ic->op)
13463         {
13464         case '!':
13465           genNot (ic);
13466           break;
13467
13468         case '~':
13469           genCpl (ic);
13470           break;
13471
13472         case UNARYMINUS:
13473           genUminus (ic);
13474           break;
13475
13476         case IPUSH:
13477           genIpush (ic);
13478           break;
13479
13480         case IPOP:
13481           /* IPOP happens only when trying to restore a
13482              spilt live range, if there is an ifx statement
13483              following this pop then the if statement might
13484              be using some of the registers being popped which
13485              would destory the contents of the register so
13486              we need to check for this condition and handle it */
13487           if (ic->next &&
13488               ic->next->op == IFX &&
13489               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
13490             genIfx (ic->next, ic);
13491           else
13492             genIpop (ic);
13493           break;
13494
13495         case CALL:
13496           genCall (ic);
13497           break;
13498
13499         case PCALL:
13500           genPcall (ic);
13501           break;
13502
13503         case FUNCTION:
13504           genFunction (ic);
13505           break;
13506
13507         case ENDFUNCTION:
13508           genEndFunction (ic);
13509           break;
13510
13511         case RETURN:
13512           genRet (ic);
13513           break;
13514
13515         case LABEL:
13516           genLabel (ic);
13517           break;
13518
13519         case GOTO:
13520           genGoto (ic);
13521           break;
13522
13523         case '+':
13524           genPlus (ic);
13525           break;
13526
13527         case '-':
13528           if (!genDjnz (ic, ifxForOp (IC_RESULT (ic), ic)))
13529             genMinus (ic);
13530           break;
13531
13532         case '*':
13533           genMult (ic);
13534           break;
13535
13536         case '/':
13537           genDiv (ic);
13538           break;
13539
13540         case '%':
13541           genMod (ic);
13542           break;
13543
13544         case '>':
13545           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
13546           break;
13547
13548         case '<':
13549           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
13550           break;
13551
13552         case LE_OP:
13553         case GE_OP:
13554         case NE_OP:
13555
13556           /* note these two are xlated by algebraic equivalence
13557              during parsing SDCC.y */
13558           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
13559                   "got '>=' or '<=' shouldn't have come here");
13560           break;
13561
13562         case EQ_OP:
13563           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
13564           break;
13565
13566         case AND_OP:
13567           genAndOp (ic);
13568           break;
13569
13570         case OR_OP:
13571           genOrOp (ic);
13572           break;
13573
13574         case '^':
13575           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
13576           break;
13577
13578         case '|':
13579           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
13580           break;
13581
13582         case BITWISEAND:
13583           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
13584           break;
13585
13586         case INLINEASM:
13587           genInline (ic);
13588           break;
13589
13590         case RRC:
13591           genRRC (ic);
13592           break;
13593
13594         case RLC:
13595           genRLC (ic);
13596           break;
13597
13598         case GETHBIT:
13599           genGetHbit (ic);
13600           break;
13601
13602         case LEFT_OP:
13603           genLeftShift (ic);
13604           break;
13605
13606         case RIGHT_OP:
13607           genRightShift (ic);
13608           break;
13609
13610         case GET_VALUE_AT_ADDRESS:
13611           genPointerGet (ic,hasInc(IC_LEFT(ic),ic, getSize(operandType(IC_RESULT(ic)))));
13612           break;
13613
13614         case '=':
13615           if (POINTER_SET (ic))
13616             genPointerSet (ic,hasInc(IC_RESULT(ic),ic,getSize(operandType(IC_RIGHT(ic)))));
13617           else
13618             genAssign (ic);
13619           break;
13620
13621         case IFX:
13622           genIfx (ic, NULL);
13623           break;
13624
13625         case ADDRESS_OF:
13626           genAddrOf (ic);
13627           break;
13628
13629         case JUMPTABLE:
13630           genJumpTab (ic);
13631           break;
13632
13633         case CAST:
13634           genCast (ic);
13635           break;
13636
13637         case RECEIVE:
13638           genReceive (ic);
13639           break;
13640
13641         case SEND:
13642           if (ic->builtinSEND) genBuiltIn(ic);
13643           else addSet (&_G.sendSet, ic);
13644           break;
13645
13646         case DUMMY_READ_VOLATILE:
13647           genDummyRead (ic);
13648           break;
13649
13650         case CRITICAL:
13651           genCritical (ic);
13652           break;
13653
13654         case ENDCRITICAL:
13655           genEndCritical (ic);
13656           break;
13657
13658         case SWAP:
13659           genSwap (ic);
13660           break;
13661
13662 #if 0 // obsolete, and buggy for != xdata
13663         case ARRAYINIT:
13664             genArrayInit(ic);
13665             break;
13666 #endif
13667
13668         default:
13669           ic = ic;
13670         }
13671     }
13672
13673
13674   /* now we are ready to call the
13675      peep hole optimizer */
13676   if (!options.nopeep)
13677     peepHole (&lineHead);
13678
13679   /* now do the actual printing */
13680   printLine (lineHead, codeOutFile);
13681   return;
13682 }