d2af3cd5dc735fdd44eda630b804cfb7a5ec7538
[fw/sdcc] / src / z80 / gen.c
1 /*-------------------------------------------------------------------------
2   gen.c - Z80 specific code generator.
3      
4   Michael Hope <michaelh@juju.net.nz> 2000
5   Based on the mcs51 generator -
6       Sandeep Dutta . sandeep.dutta@usa.net (1998)
7    and -  Jean-Louis VERN.jlvern@writeme.com (1999)
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
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24   In other words, you are welcome to use, share and improve this program.
25   You are forbidden to forbid anyone else to use, share and improve
26   what you give them.   Help stamp out software-hoarding!
27
28 -------------------------------------------------------------------------*/
29
30 /*
31   Benchmarks on dhry.c 2.1 with 32766 loops and a 10ms clock:
32                                        ticks dhry  size
33   Base with asm strcpy / strcmp / memcpy: 23198 141 1A14
34   Improved WORD push                    22784 144 19AE
35   With label1 on                        22694 144 197E
36   With label2 on                        22743 144 198A
37   With label3 on                        22776 144 1999
38   With label4 on                        22776 144 1999
39   With all 'label' on                   22661 144 196F
40   With loopInvariant on                 20919 156 19AB
41   With loopInduction on                 Breaks    198B
42   With all working on                   20796 158 196C
43   Slightly better genCmp(signed)        20597 159 195B
44   Better reg packing, first peephole    20038 163 1873
45   With assign packing                   19281 165 1849
46   5/3/00                                17741 185 17B6
47   With reg params for mul and div       16234 202 162D
48
49   1. Starting again at 3 Aug 01         34965  93 219C
50    No asm strings
51    Includes long mul/div in code
52   2. Optimised memcpy for acc use       32102 102 226B
53   3. Optimised strcpy for acc use       27819 117 2237
54   3a Optimised memcpy fun
55   4. Optimised strcmp fun               21999 149 2294
56   5. Optimised strcmp further           21660 151 228C
57   6. Optimised memcpy by unroling       20885 157 2201
58   7. After turning loop induction on    19862 165 236D
59   8. Same as 7 but with more info       
60   9. With asm optimised strings         17030 192 2223
61
62   10 and below are with asm strings off.
63   
64   Apparent advantage of turning on regparams:
65   1.  Cost of push
66         Decent case is push of a constant 
67           - ld hl,#n; push hl: (10+11)*nargs
68   2.  Cost of pull from stack
69         Using asm with ld hl, etc
70           - ld hl,#2; add hl,sp; (ld bc,(hl); hl+=2)*nargs
71             10+11+(7+6+7+6)*nargs
72   3.  Cost of fixing stack
73           - pop hl*nargs
74             10*nargs
75   
76   So cost is (10+11+7+6+7+10)*nargs+10+11 
77       = 51*nargs+21
78       = 123 for mul, div, strcmp, strcpy
79   Saving of (98298+32766+32766+32766)*123 = 24181308
80   At 192 d/s for 682411768t, speed up to 199.  Hmm.
81 */
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <ctype.h>
87
88 #ifdef HAVE_SYS_ISA_DEFS_H
89 #include <sys/isa_defs.h>
90 #endif
91
92 #include "z80.h"
93 #include "SDCCglobl.h"
94 #include "SDCCpeeph.h"
95 #include "gen.h"
96 #include "SDCCglue.h"
97 #include "newalloc.h"
98
99 /* This is the down and dirty file with all kinds of kludgy & hacky
100    stuff. This is what it is all about CODE GENERATION for a specific MCU.
101    Some of the routines may be reusable, will have to see */
102
103 /* Z80 calling convention description.
104    Parameters are passed right to left.  As the stack grows downwards,
105    the parameters are arranged in left to right in memory.
106    Parameters may be passed in the HL and DE registers with one
107    parameter per pair.
108    PENDING: What if the parameter is a long?
109    Everything is caller saves. i.e. the caller must save any registers
110    that it wants to preserve over the call.
111    GB: The return value is returned in DEHL.  DE is normally used as a
112    working register pair.  Caller saves allows it to be used for a
113    return value.
114    va args functions do not use register parameters.  All arguments
115    are passed on the stack.
116    IX is used as an index register to the top of the local variable
117    area.  ix-0 is the top most local variable.
118 */
119
120 enum 
121 {
122   /* Set to enable debugging trace statements in the output assembly code. */
123   DISABLE_DEBUG = 0
124 };
125
126 static char *_z80_return[] =
127 {"l", "h", "e", "d"};
128 static char *_gbz80_return[] =
129 {"e", "d", "l", "h"};
130 static char *_fReceive[] =
131   { "c", "b", "e", "d" };
132
133 static char **_fReturn;
134 static char **_fTmp;
135
136 extern FILE *codeOutFile;
137
138 enum
139   {
140     INT8MIN = -128,
141     INT8MAX = 127
142   };
143
144 /** Enum covering all the possible register pairs.
145  */
146 typedef enum
147   {
148     PAIR_INVALID,
149     PAIR_AF,
150     PAIR_BC,
151     PAIR_DE,
152     PAIR_HL,
153     PAIR_IY,
154     PAIR_IX,
155     NUM_PAIRS
156   } PAIR_ID;
157
158 static struct
159 {
160   const char *name;
161   const char *l;
162   const char *h;
163 } _pairs[NUM_PAIRS] = {
164   {    "??1", "?2", "?3" },
165   {    "af", "f", "a" },
166   {    "bc", "c", "b" },
167   {    "de", "e", "d" },
168   {    "hl", "l", "h" },
169   {    "iy", "iyl", "iyh" },
170   {    "ix", "ixl", "ixh" }
171 };
172
173 // PENDING
174 #define ACC_NAME        _pairs[PAIR_AF].h
175
176 enum 
177   {
178     LSB,
179     MSB16,
180     MSB24,
181     MSB32
182   };
183
184 /** Code generator persistent data.
185  */
186 static struct 
187 {
188   /** Used to optimised setting up of a pair by remebering what it
189       contains and adjusting instead of reloading where possible.
190   */
191   struct 
192   {
193     AOP_TYPE last_type;
194     const char *base;
195     int offset;
196   } pairs[NUM_PAIRS];
197   struct 
198   {
199     int last;
200     int pushed;
201     int param_offset;
202     int offset;
203     int pushedBC;
204     int pushedDE;
205   } stack;
206   int frameId;
207   int receiveOffset;
208   bool flushStatics;
209   bool in_home;
210   const char *lastFunctionName;
211
212   set *sendSet;
213
214   struct
215   {
216     /** TRUE if the registers have already been saved. */
217     bool saved;
218   } saves;
219
220   struct 
221   {
222     lineNode *head;
223     lineNode *current;
224     int isInline;
225     allocTrace trace;
226   } lines;
227
228   struct
229   {
230     allocTrace aops;
231   } trace;
232 } _G;
233
234 static const char *aopGet (asmop * aop, int offset, bool bit16);
235
236 static PAIR_ID
237 _getTempPairId(void)
238 {
239   if (IS_GB)
240     {
241       return PAIR_DE;
242     }
243   else
244     {
245       return PAIR_HL;
246     }
247 }
248
249 static const char *
250 _getTempPairName(void)
251 {
252   return _pairs[_getTempPairId()].name;
253 }
254
255 static PAIR_ID
256 getFreePairId (iCode *ic)
257 {
258   if (!(bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue(ic->rMask, C_IDX)))
259     {
260       return PAIR_BC;
261     }
262   else if (IS_Z80 && !(bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX)))
263     {
264       return PAIR_DE;
265     }
266   else
267     {
268       return PAIR_INVALID;
269     }
270 }         
271
272 static void
273 _tidyUp (char *buf)
274 {
275   /* Clean up the line so that it is 'prettier' */
276   if (strchr (buf, ':'))
277     {
278       /* Is a label - cant do anything */
279       return;
280     }
281   /* Change the first (and probably only) ' ' to a tab so
282      everything lines up.
283   */
284   while (*buf)
285     {
286       if (*buf == ' ')
287         {
288           *buf = '\t';
289           break;
290         }
291       buf++;
292     }
293 }
294
295 static lineNode *
296 _newLineNode (char *line)
297 {
298   lineNode *pl;
299
300   pl = traceAlloc(&_G.lines.trace, Safe_alloc ( sizeof (lineNode)));
301   pl->line = traceAlloc(&_G.lines.trace, Safe_strdup (line));
302
303   return pl;
304 }
305
306 static void
307 _vemit2 (const char *szFormat, va_list ap)
308 {
309   char buffer[256];
310
311   tvsprintf (buffer, szFormat, ap);
312
313   _tidyUp (buffer);
314   _G.lines.current = (_G.lines.current ?
315               connectLine (_G.lines.current, _newLineNode (buffer)) :
316               (_G.lines.head = _newLineNode (buffer)));
317
318   _G.lines.current->isInline = _G.lines.isInline;
319 }
320
321 static void
322 emit2 (const char *szFormat,...)
323 {
324   va_list ap;
325
326   va_start (ap, szFormat);
327
328   _vemit2 (szFormat, ap);
329
330   va_end (ap);
331 }
332
333 static void
334 emitDebug (const char *szFormat,...)
335 {
336   if (!DISABLE_DEBUG)
337     {
338       va_list ap;
339       
340       va_start (ap, szFormat);
341       
342       _vemit2 (szFormat, ap);
343       
344       va_end (ap);
345     }
346 }
347
348 /*-----------------------------------------------------------------*/
349 /* emit2 - writes the code into a file : for now it is simple    */
350 /*-----------------------------------------------------------------*/
351 void
352 _emit2 (const char *inst, const char *fmt,...)
353 {
354   va_list ap;
355   char lb[INITIAL_INLINEASM];
356   char *lbp = lb;
357
358   va_start (ap, fmt);
359
360   if (*inst != '\0')
361     {
362       sprintf (lb, "%s\t", inst);
363       vsprintf (lb + (strlen (lb)), fmt, ap);
364     }
365   else
366     vsprintf (lb, fmt, ap);
367
368   while (isspace (*lbp))
369     lbp++;
370
371   if (lbp && *lbp)
372     {
373       _G.lines.current = (_G.lines.current ?
374                   connectLine (_G.lines.current, _newLineNode (lb)) :
375                   (_G.lines.head = _newLineNode (lb)));
376     }
377   _G.lines.current->isInline = _G.lines.isInline;
378   va_end (ap);
379 }
380
381 static void
382 _emitMove(const char *to, const char *from)
383 {
384   if (strcasecmp(to, from) != 0) 
385     {
386       emit2("ld %s,%s", to, from);
387     }
388   else 
389     {
390       // Optimise it out.
391       // Could leave this to the peephole, but sometimes the peephole is inhibited.
392     }
393 }
394
395 static void
396 _moveA(const char *moveFrom)
397 {
398     // Let the peephole optimiser take care of redundent loads
399     _emitMove(ACC_NAME, moveFrom);
400 }
401
402 static void
403 _clearCarry(void)
404 {
405     emit2("xor a,a");
406 }
407
408 const char *
409 getPairName (asmop * aop)
410 {
411   if (aop->type == AOP_REG)
412     {
413       switch (aop->aopu.aop_reg[0]->rIdx)
414         {
415         case C_IDX:
416           return "bc";
417           break;
418         case E_IDX:
419           return "de";
420           break;
421         case L_IDX:
422           return "hl";
423           break;
424         }
425     }
426   else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
427     {
428       int i;
429       for (i = 0; i < NUM_PAIRS; i++)
430         {
431           if (strcmp(aop->aopu.aop_str[0], _pairs[i].l) == 0)
432             {
433               return _pairs[i].name;
434             }
435         }
436     }
437   wassertl (0, "Tried to get the pair name of something that isn't a pair");
438   return NULL;
439 }
440
441 static PAIR_ID
442 getPairId (asmop * aop)
443 {
444   if (aop->size == 2)
445     {
446       if (aop->type == AOP_REG)
447         {
448           if ((aop->aopu.aop_reg[0]->rIdx == C_IDX) && (aop->aopu.aop_reg[1]->rIdx == B_IDX))
449             {
450               return PAIR_BC;
451             }
452           if ((aop->aopu.aop_reg[0]->rIdx == E_IDX) && (aop->aopu.aop_reg[1]->rIdx == D_IDX))
453             {
454               return PAIR_DE;
455             }
456           if ((aop->aopu.aop_reg[0]->rIdx == L_IDX) && (aop->aopu.aop_reg[1]->rIdx == H_IDX))
457             {
458               return PAIR_HL;
459             }
460         }
461       else if (aop->type == AOP_STR || aop->type == AOP_HLREG)
462         {
463           int i;
464           for (i = 0; i < NUM_PAIRS; i++)
465             {
466               if (!strcmp (aop->aopu.aop_str[0], _pairs[i].l) && !strcmp (aop->aopu.aop_str[1], _pairs[i].h))
467                 {
468                   return i;
469                 }
470             }
471         }
472     }
473   return PAIR_INVALID;
474 }
475
476 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
477 bool
478 isPair (asmop * aop)
479 {
480   return (getPairId (aop) != PAIR_INVALID);
481 }
482
483 bool
484 isPtrPair (asmop * aop)
485 {
486   PAIR_ID pairId = getPairId (aop);
487   switch (pairId)
488     {
489     case PAIR_HL:
490     case PAIR_IY:
491     case PAIR_IX:
492       return TRUE;
493     default:
494       return FALSE;
495     }
496 }
497
498 static void
499 spillPair (PAIR_ID pairId)
500 {
501   _G.pairs[pairId].last_type = AOP_INVALID;
502   _G.pairs[pairId].base = NULL;
503 }
504
505 /** Push a register pair onto the stack */
506 void
507 genPairPush (asmop * aop)
508 {
509   emit2 ("push %s", getPairName (aop));
510 }
511
512 static void
513 _push (PAIR_ID pairId)
514 {
515   emit2 ("push %s", _pairs[pairId].name);
516   _G.stack.pushed += 2;
517 }
518
519 static void
520 _pop (PAIR_ID pairId)
521 {
522   emit2 ("pop %s", _pairs[pairId].name);
523   _G.stack.pushed -= 2;
524   spillPair (pairId);
525 }
526
527 /*-----------------------------------------------------------------*/
528 /* newAsmop - creates a new asmOp                                  */
529 /*-----------------------------------------------------------------*/
530 static asmop *
531 newAsmop (short type)
532 {
533   asmop *aop;
534
535   aop = traceAlloc(&_G.trace.aops, Safe_alloc (sizeof (asmop)));
536   aop->type = type;
537   return aop;
538 }
539
540 /*-----------------------------------------------------------------*/
541 /* aopForSym - for a true symbol                                   */
542 /*-----------------------------------------------------------------*/
543 static asmop *
544 aopForSym (iCode * ic, symbol * sym, bool result, bool requires_a)
545 {
546   asmop *aop;
547   memmap *space;
548
549   wassert (ic);
550   wassert (sym);
551   wassert (sym->etype);
552
553   space = SPEC_OCLS (sym->etype);
554
555   /* if already has one */
556   if (sym->aop)
557     return sym->aop;
558
559   /* Assign depending on the storage class */
560   if (sym->onStack || sym->iaccess)
561     {
562       /* The pointer that is used depends on how big the offset is.
563          Normally everything is AOP_STK, but for offsets of < -128 or
564          > 127 on the Z80 an extended stack pointer is used.
565       */
566       if (IS_Z80 && (options.ommitFramePtr || sym->stack < INT8MIN || sym->stack > (int)(INT8MAX-getSize (sym->type))))
567         {
568           emitDebug ("; AOP_EXSTK for %s", sym->rname);
569           sym->aop = aop = newAsmop (AOP_EXSTK);
570         }
571       else
572         {
573           emitDebug ("; AOP_STK for %s", sym->rname);
574           sym->aop = aop = newAsmop (AOP_STK);
575         }
576
577       aop->size = getSize (sym->type);
578       aop->aopu.aop_stk = sym->stack;
579       return aop;
580     }
581
582   /* special case for a function */
583   if (IS_FUNC (sym->type))
584     {
585       sym->aop = aop = newAsmop (AOP_IMMD);
586       aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup (sym->rname));
587       aop->size = 2;
588       return aop;
589     }
590
591   if (IS_GB)
592     {
593       /* if it is in direct space */
594       if (IN_REGSP (space) && !requires_a)
595         {
596           sym->aop = aop = newAsmop (AOP_SFR);
597           aop->aopu.aop_dir = sym->rname;
598           aop->size = getSize (sym->type);
599           emitDebug ("; AOP_SFR for %s", sym->rname);
600           return aop;
601         }
602     }
603
604   /* only remaining is far space */
605   /* in which case DPTR gets the address */
606   if (IS_GB)
607     {
608       emitDebug ("; AOP_HL for %s", sym->rname);
609       sym->aop = aop = newAsmop (AOP_HL);
610     }
611   else
612     {
613       sym->aop = aop = newAsmop (AOP_IY);
614     }
615   aop->size = getSize (sym->type);
616   aop->aopu.aop_dir = sym->rname;
617
618   /* if it is in code space */
619   if (IN_CODESPACE (space))
620     aop->code = 1;
621
622   return aop;
623 }
624
625 /*-----------------------------------------------------------------*/
626 /* aopForRemat - rematerialzes an object                           */
627 /*-----------------------------------------------------------------*/
628 static asmop *
629 aopForRemat (symbol * sym)
630 {
631   char *s = buffer;
632   iCode *ic = sym->rematiCode;
633   asmop *aop = newAsmop (AOP_IMMD);
634
635   while (1)
636     {
637       /* if plus or minus print the right hand side */
638       if (ic->op == '+' || ic->op == '-')
639         {
640           /* PENDING: for re-target */
641           sprintf (s, "0x%04x %c ", (int) operandLitValue (IC_RIGHT (ic)),
642                    ic->op);
643           s += strlen (s);
644           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
645           continue;
646         }
647       /* we reached the end */
648       sprintf (s, "%s", OP_SYMBOL (IC_LEFT (ic))->rname);
649       break;
650     }
651
652   aop->aopu.aop_immd = traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
653   return aop;
654 }
655
656 /*-----------------------------------------------------------------*/
657 /* regsInCommon - two operands have some registers in common       */
658 /*-----------------------------------------------------------------*/
659 bool
660 regsInCommon (operand * op1, operand * op2)
661 {
662   symbol *sym1, *sym2;
663   int i;
664
665   /* if they have registers in common */
666   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
667     return FALSE;
668
669   sym1 = OP_SYMBOL (op1);
670   sym2 = OP_SYMBOL (op2);
671
672   if (sym1->nRegs == 0 || sym2->nRegs == 0)
673     return FALSE;
674
675   for (i = 0; i < sym1->nRegs; i++)
676     {
677       int j;
678       if (!sym1->regs[i])
679         continue;
680
681       for (j = 0; j < sym2->nRegs; j++)
682         {
683           if (!sym2->regs[j])
684             continue;
685
686           if (sym2->regs[j] == sym1->regs[i])
687             return TRUE;
688         }
689     }
690
691   return FALSE;
692 }
693
694 /*-----------------------------------------------------------------*/
695 /* operandsEqu - equivalent                                        */
696 /*-----------------------------------------------------------------*/
697 bool
698 operandsEqu (operand * op1, operand * op2)
699 {
700   symbol *sym1, *sym2;
701
702   /* if they not symbols */
703   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
704     return FALSE;
705
706   sym1 = OP_SYMBOL (op1);
707   sym2 = OP_SYMBOL (op2);
708
709   /* if both are itemps & one is spilt
710      and the other is not then false */
711   if (IS_ITEMP (op1) && IS_ITEMP (op2) &&
712       sym1->isspilt != sym2->isspilt)
713     return FALSE;
714
715   /* if they are the same */
716   if (sym1 == sym2)
717     return 1;
718
719   if (strcmp (sym1->rname, sym2->rname) == 0)
720     return 2;
721
722
723   /* if left is a tmp & right is not */
724   if (IS_ITEMP (op1) &&
725       !IS_ITEMP (op2) &&
726       sym1->isspilt &&
727       (sym1->usl.spillLoc == sym2))
728     return 3;
729
730   if (IS_ITEMP (op2) &&
731       !IS_ITEMP (op1) &&
732       sym2->isspilt &&
733       sym1->level > 0 &&
734       (sym2->usl.spillLoc == sym1))
735     return 4;
736
737   return FALSE;
738 }
739
740 /*-----------------------------------------------------------------*/
741 /* sameRegs - two asmops have the same registers                   */
742 /*-----------------------------------------------------------------*/
743 bool
744 sameRegs (asmop * aop1, asmop * aop2)
745 {
746   int i;
747
748   if (aop1->type == AOP_SFR ||
749       aop2->type == AOP_SFR)
750     return FALSE;
751
752   if (aop1 == aop2)
753     return TRUE;
754
755   if (aop1->type != AOP_REG ||
756       aop2->type != AOP_REG)
757     return FALSE;
758
759   if (aop1->size != aop2->size)
760     return FALSE;
761
762   for (i = 0; i < aop1->size; i++)
763     if (aop1->aopu.aop_reg[i] !=
764         aop2->aopu.aop_reg[i])
765       return FALSE;
766
767   return TRUE;
768 }
769
770 /*-----------------------------------------------------------------*/
771 /* aopOp - allocates an asmop for an operand  :                    */
772 /*-----------------------------------------------------------------*/
773 static void
774 aopOp (operand * op, iCode * ic, bool result, bool requires_a)
775 {
776   asmop *aop;
777   symbol *sym;
778   int i;
779
780   if (!op)
781     return;
782
783   /* if this a literal */
784   if (IS_OP_LITERAL (op))
785     {
786       op->aop = aop = newAsmop (AOP_LIT);
787       aop->aopu.aop_lit = op->operand.valOperand;
788       aop->size = getSize (operandType (op));
789       return;
790     }
791
792   /* if already has a asmop then continue */
793   if (op->aop)
794     return;
795
796   /* if the underlying symbol has a aop */
797   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
798     {
799       op->aop = OP_SYMBOL (op)->aop;
800       return;
801     }
802
803   /* if this is a true symbol */
804   if (IS_TRUE_SYMOP (op))
805     {
806       op->aop = aopForSym (ic, OP_SYMBOL (op), result, requires_a);
807       return;
808     }
809
810   /* this is a temporary : this has
811      only four choices :
812      a) register
813      b) spillocation
814      c) rematerialize
815      d) conditional
816      e) can be a return use only */
817
818   sym = OP_SYMBOL (op);
819
820   /* if the type is a conditional */
821   if (sym->regType == REG_CND)
822     {
823       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
824       aop->size = 0;
825       return;
826     }
827
828   /* if it is spilt then two situations
829      a) is rematerialize
830      b) has a spill location */
831   if (sym->isspilt || sym->nRegs == 0)
832     {
833       /* rematerialize it NOW */
834       if (sym->remat)
835         {
836           sym->aop = op->aop = aop =
837             aopForRemat (sym);
838           aop->size = getSize (sym->type);
839           return;
840         }
841
842       if (sym->ruonly)
843         {
844           int i;
845           aop = op->aop = sym->aop = newAsmop (AOP_STR);
846           aop->size = getSize (sym->type);
847           for (i = 0; i < 4; i++)
848             aop->aopu.aop_str[i] = _fReturn[i];
849           return;
850         }
851
852       if (sym->accuse)
853         {
854           if (sym->accuse == ACCUSE_A)
855             {
856               aop = op->aop = sym->aop = newAsmop (AOP_ACC);
857               aop->size = getSize (sym->type);
858               wassertl(aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
859
860               aop->aopu.aop_str[0] = _pairs[PAIR_AF].h;
861             }
862           else if (sym->accuse == ACCUSE_SCRATCH)
863             {
864               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
865               aop->size = getSize (sym->type);
866               wassertl(aop->size <= 2, "Internal error: Caching in HL, but too big to fit in HL");
867               aop->aopu.aop_str[0] = _pairs[PAIR_HL].l;
868               aop->aopu.aop_str[1] = _pairs[PAIR_HL].h;
869             }
870           else if (sym->accuse == ACCUSE_IY)
871             {
872               aop = op->aop = sym->aop = newAsmop (AOP_HLREG);
873               aop->size = getSize (sym->type);
874               wassertl(aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
875               aop->aopu.aop_str[0] = _pairs[PAIR_IY].l;
876               aop->aopu.aop_str[1] = _pairs[PAIR_IY].h;
877             }
878           else 
879               {
880                   wassertl (0, "Marked as being allocated into A or HL but is actually in neither");
881               }
882           return;
883         }
884
885       /* else spill location  */
886       sym->aop = op->aop = aop =
887         aopForSym (ic, sym->usl.spillLoc, result, requires_a);
888       aop->size = getSize (sym->type);
889       return;
890     }
891
892   /* must be in a register */
893   sym->aop = op->aop = aop = newAsmop (AOP_REG);
894   aop->size = sym->nRegs;
895   for (i = 0; i < sym->nRegs; i++)
896     aop->aopu.aop_reg[i] = sym->regs[i];
897 }
898
899 /*-----------------------------------------------------------------*/
900 /* freeAsmop - free up the asmop given to an operand               */
901 /*----------------------------------------------------------------*/
902 static void
903 freeAsmop (operand * op, asmop * aaop, iCode * ic)
904 {
905   asmop *aop;
906
907   if (!op)
908     aop = aaop;
909   else
910     aop = op->aop;
911
912   if (!aop)
913     return;
914
915   if (aop->freed)
916     goto dealloc;
917
918   aop->freed = 1;
919
920   if (aop->type == AOP_PAIRPTR && IS_Z80 && aop->aopu.aop_pairId == PAIR_DE)
921     {
922       _pop (aop->aopu.aop_pairId);
923     }
924
925 dealloc:
926   /* all other cases just dealloc */
927   if (op)
928     {
929       op->aop = NULL;
930       if (IS_SYMOP (op))
931         {
932           OP_SYMBOL (op)->aop = NULL;
933           /* if the symbol has a spill */
934           if (SPIL_LOC (op))
935             SPIL_LOC (op)->aop = NULL;
936         }
937     }
938
939 }
940
941 bool
942 isLitWord (asmop * aop)
943 {
944   /*    if (aop->size != 2)
945      return FALSE; */
946   switch (aop->type)
947     {
948     case AOP_IMMD:
949     case AOP_LIT:
950       return TRUE;
951     default:
952       return FALSE;
953     }
954 }
955
956 char *
957 aopGetLitWordLong (asmop * aop, int offset, bool with_hash)
958 {
959   char *s = buffer;
960
961   /* depending on type */
962   switch (aop->type)
963     {
964     case AOP_HL:
965     case AOP_IY:
966     case AOP_IMMD:
967       /* PENDING: for re-target */
968       if (with_hash)
969         {
970           tsprintf (s, "!hashedstr + %d", aop->aopu.aop_immd, offset);
971         }
972       else if (offset == 0)
973         {
974           tsprintf (s, "%s", aop->aopu.aop_immd);
975         }
976       else
977         {
978           tsprintf (s, "%s + %d", aop->aopu.aop_immd, offset);
979         }
980       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
981
982     case AOP_LIT:
983       {
984         value *val = aop->aopu.aop_lit;
985         /* if it is a float then it gets tricky */
986         /* otherwise it is fairly simple */
987         if (!IS_FLOAT (val->type))
988           {
989             unsigned long v = (unsigned long) floatFromVal (val);
990
991             if (offset == 2)
992               {
993                 v >>= 16;
994               }
995             else if (offset == 0)
996               {
997                 // OK
998               }
999             else 
1000               {
1001                 wassertl(0, "Encountered an invalid offset while fetching a literal");
1002               }
1003
1004             if (with_hash)
1005               tsprintf (buffer, "!immedword", v);
1006             else
1007               tsprintf (buffer, "!constword", v);
1008
1009             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1010           }
1011         else
1012           {
1013             union {
1014               float f;
1015               unsigned char c[4];
1016             }
1017             fl;
1018             unsigned int i;
1019
1020             /* it is type float */
1021             fl.f = (float) floatFromVal (val);
1022
1023 #ifdef _BIG_ENDIAN
1024             i = fl.c[3-offset] | (fl.c[3-offset-1]<<8);
1025 #else
1026             i = fl.c[offset] | (fl.c[offset+1]<<8);
1027 #endif
1028             if (with_hash)
1029               tsprintf (buffer, "!immedword", i);
1030             else
1031               tsprintf (buffer, "!constword", i);
1032
1033             return traceAlloc(&_G.trace.aops, Safe_strdup(buffer));
1034           }
1035       }
1036     default:
1037       return NULL;
1038     }
1039 }
1040
1041 char *
1042 aopGetWord (asmop * aop, int offset)
1043 {
1044   return aopGetLitWordLong (aop, offset, TRUE);
1045 }
1046
1047 bool
1048 isPtr (const char *s)
1049 {
1050   if (!strcmp (s, "hl"))
1051     return TRUE;
1052   if (!strcmp (s, "ix"))
1053     return TRUE;
1054   if (!strcmp (s, "iy"))
1055     return TRUE;
1056   return FALSE;
1057 }
1058
1059 static void
1060 adjustPair (const char *pair, int *pold, int new)
1061 {
1062   wassert (pair);
1063
1064   while (*pold < new)
1065     {
1066       emit2 ("inc %s", pair);
1067       (*pold)++;
1068     }
1069   while (*pold > new)
1070     {
1071       emit2 ("dec %s", pair);
1072       (*pold)--;
1073     }
1074 }
1075
1076 static void
1077 spillCached (void)
1078 {
1079   spillPair (PAIR_HL);
1080   spillPair (PAIR_IY);
1081 }
1082
1083 static bool
1084 requiresHL (asmop * aop)
1085 {
1086   switch (aop->type)
1087     {
1088     case AOP_IY:
1089     case AOP_HL:
1090     case AOP_STK:
1091     case AOP_EXSTK:
1092     case AOP_HLREG:
1093       return TRUE;
1094     default:
1095       return FALSE;
1096     }
1097 }
1098
1099 static void
1100 fetchLitPair (PAIR_ID pairId, asmop * left, int offset)
1101 {
1102   const char *l, *base;
1103   const char *pair = _pairs[pairId].name;
1104   l = aopGetLitWordLong (left, offset, FALSE);
1105   base = aopGetLitWordLong (left, 0, FALSE);
1106   wassert (l && pair && base);
1107
1108   if (isPtr (pair))
1109     {
1110       if (pairId == PAIR_HL || pairId == PAIR_IY)
1111         {
1112           if (_G.pairs[pairId].last_type == left->type)
1113             {
1114               if (_G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))
1115                 {
1116                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1117                     {
1118                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1119                       return;
1120                     }
1121                   if (pairId == PAIR_IY && (offset >= INT8MIN && offset <= INT8MAX))
1122                     {
1123                       return;
1124                     }
1125                 }
1126             }
1127         }
1128       _G.pairs[pairId].last_type = left->type;
1129       _G.pairs[pairId].base = traceAlloc(&_G.trace.aops, Safe_strdup (base));
1130       _G.pairs[pairId].offset = offset;
1131     }
1132   /* Both a lit on the right and a true symbol on the left */
1133   emit2 ("ld %s,!hashedstr", pair, l);
1134 }
1135
1136 static void
1137 fetchPairLong (PAIR_ID pairId, asmop * aop, int offset)
1138 {
1139     /* if this is remateriazable */
1140     if (isLitWord (aop)) {
1141         fetchLitPair (pairId, aop, offset);
1142     }
1143     else 
1144       {
1145         if (getPairId (aop) == pairId)
1146           {
1147             /* Do nothing */
1148           }
1149         /* we need to get it byte by byte */
1150         else if (pairId == PAIR_HL && IS_GB && requiresHL (aop)) {
1151             aopGet (aop, offset, FALSE);
1152             switch (aop->size - offset) {
1153             case 1:
1154                 emit2 ("ld l,!*hl");
1155                 emit2 ("ld h,!immedbyte", 0);
1156                             break;
1157             case 2:
1158               // PENDING: Requires that you are only fetching two bytes.
1159             case 4:
1160                 emit2 ("!ldahli");
1161                 emit2 ("ld h,!*hl");
1162                 emit2 ("ld l,a");
1163                 break;
1164             default:
1165               wassertl (0, "Attempted to fetch too much data into HL");
1166               break;
1167             }
1168         }
1169         else if (IS_Z80 && aop->type == AOP_IY) {
1170             /* Instead of fetching relative to IY, just grab directly
1171                from the address IY refers to */
1172             char *l = aopGetLitWordLong (aop, offset, FALSE);
1173             wassert (l);
1174             emit2 ("ld %s,(%s)", _pairs[pairId].name, l);
1175
1176             if (aop->size < 2) {
1177                 emit2("ld %s,!zero", _pairs[pairId].h);
1178             }
1179         }
1180         else if (pairId == PAIR_IY)
1181           {
1182             if (isPair (aop))
1183               {
1184                 emit2 ("push %s", _pairs[getPairId(aop)].name);
1185                 emit2 ("pop iy");
1186               }
1187             else
1188               {
1189                 _push (PAIR_HL);
1190                 /* Can't load into parts, so load into HL then exchange. */
1191                 emit2 ("ld %s,%s", _pairs[PAIR_HL].l, aopGet (aop, offset, FALSE));
1192                 emit2 ("ld %s,%s", _pairs[PAIR_HL].h, aopGet (aop, offset + 1, FALSE));
1193                 emit2 ("push hl");
1194                 emit2 ("pop iy");
1195                 _pop (PAIR_HL);
1196               }
1197           }
1198         else {
1199             emit2 ("ld %s,%s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
1200             emit2 ("ld %s,%s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
1201         }
1202         /* PENDING: check? */
1203         if (pairId == PAIR_HL)
1204             spillPair (PAIR_HL);
1205     }
1206 }
1207
1208 static void
1209 fetchPair (PAIR_ID pairId, asmop * aop)
1210 {
1211   fetchPairLong (pairId, aop, 0);
1212 }
1213
1214 static void
1215 fetchHL (asmop * aop)
1216 {
1217   fetchPair (PAIR_HL, aop);
1218 }
1219
1220 static void
1221 setupPairFromSP (PAIR_ID id, int offset)
1222 {
1223   wassertl (id == PAIR_HL, "Setup relative to SP only implemented for HL");
1224
1225   if (offset < INT8MIN || offset > INT8MAX)
1226     {
1227       emit2 ("ld hl,!immedword", offset);
1228       emit2 ("add hl,sp");
1229     }
1230   else
1231     {
1232       emit2 ("!ldahlsp", offset);
1233     }
1234 }
1235
1236 static void
1237 setupPair (PAIR_ID pairId, asmop * aop, int offset)
1238 {
1239   switch (aop->type)
1240     {
1241     case AOP_IY:
1242       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
1243       fetchLitPair (pairId, aop, 0);
1244       break;
1245
1246     case AOP_HL:
1247       wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
1248       
1249       fetchLitPair (pairId, aop, offset);
1250       _G.pairs[pairId].offset = offset;
1251       break;
1252
1253     case AOP_EXSTK:
1254       wassertl (IS_Z80, "Only the Z80 has an extended stack");
1255       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
1256
1257       {
1258         int offset = aop->aopu.aop_stk + _G.stack.offset;
1259
1260         if (_G.pairs[pairId].last_type == aop->type &&
1261             _G.pairs[pairId].offset == offset)
1262           {
1263             /* Already setup */
1264           }
1265         else
1266           {
1267             /* PENDING: Do this better. */
1268             sprintf (buffer, "%d", offset + _G.stack.pushed);
1269             emit2 ("ld %s,!hashedstr", _pairs[pairId].name, buffer);
1270             emit2 ("add %s,sp", _pairs[pairId].name);
1271             _G.pairs[pairId].last_type = aop->type;
1272             _G.pairs[pairId].offset = offset;
1273           }
1274       }
1275       break;
1276
1277     case AOP_STK:
1278       {
1279         /* Doesnt include _G.stack.pushed */
1280         int abso = aop->aopu.aop_stk + offset + _G.stack.offset;
1281         if (aop->aopu.aop_stk > 0)
1282           {
1283             abso += _G.stack.param_offset;
1284           }
1285         assert (pairId == PAIR_HL);
1286         /* In some cases we can still inc or dec hl */
1287         if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
1288           {
1289             adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
1290           }
1291         else
1292           {
1293             setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
1294           }
1295         _G.pairs[pairId].offset = abso;
1296         break;
1297       }
1298
1299     case AOP_PAIRPTR:
1300       adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
1301       break;
1302       
1303     default:
1304       wassert (0);
1305     }
1306   _G.pairs[pairId].last_type = aop->type;
1307 }
1308
1309 static void
1310 emitLabel (int key)
1311 {
1312   emit2 ("!tlabeldef", key);
1313   spillCached ();
1314 }
1315
1316 /*-----------------------------------------------------------------*/
1317 /* aopGet - for fetching value of the aop                          */
1318 /*-----------------------------------------------------------------*/
1319 static const char *
1320 aopGet (asmop * aop, int offset, bool bit16)
1321 {
1322   char *s = buffer;
1323
1324   /* offset is greater than size then zero */
1325   /* PENDING: this seems a bit screwed in some pointer cases. */
1326   if (offset > (aop->size - 1) &&
1327       aop->type != AOP_LIT) 
1328     {
1329       tsprintf (s, "!zero");
1330       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1331     }
1332
1333   /* depending on type */
1334   switch (aop->type)
1335     {
1336     case AOP_IMMD:
1337       /* PENDING: re-target */
1338       if (bit16)
1339         tsprintf (s, "!immedwords", aop->aopu.aop_immd);
1340       else
1341         switch (offset)
1342           {
1343           case 2:
1344             tsprintf (s, "!bankimmeds", aop->aopu.aop_immd);
1345             break;
1346           case 1:
1347             tsprintf (s, "!msbimmeds", aop->aopu.aop_immd);
1348             break;
1349           case 0:
1350             tsprintf (s, "!lsbimmeds", aop->aopu.aop_immd);
1351             break;
1352           default:
1353             wassertl (0, "Fetching from beyond the limits of an immediate value.");
1354           }
1355
1356       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1357
1358     case AOP_DIR:
1359       wassert (IS_GB);
1360       emit2 ("ld a,(%s+%d)", aop->aopu.aop_dir, offset);
1361       sprintf (s, "a");
1362
1363       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1364
1365     case AOP_SFR:
1366       wassert (IS_GB);
1367       emit2 ("ldh a,(%s+%d)", aop->aopu.aop_dir, offset);
1368       sprintf (s, "a");
1369
1370       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1371
1372     case AOP_REG:
1373       return aop->aopu.aop_reg[offset]->name;
1374
1375     case AOP_HL:
1376       wassert (IS_GB);
1377       setupPair (PAIR_HL, aop, offset);
1378       tsprintf (s, "!*hl");
1379
1380       return traceAlloc(&_G.trace.aops, Safe_strdup (s));
1381
1382     case AOP_IY:
1383       wassert (IS_Z80);
1384       setupPair (PAIR_IY, aop, offset);
1385       tsprintf (s, "!*iyx", offset);
1386
1387       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1388
1389     case AOP_EXSTK:
1390       wassert (IS_Z80);
1391       setupPair (PAIR_IY, aop, offset);
1392       tsprintf (s, "!*iyx", offset, offset);
1393
1394       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1395
1396     case AOP_STK:
1397       if (IS_GB)
1398         {
1399           setupPair (PAIR_HL, aop, offset);
1400           tsprintf (s, "!*hl");
1401         }
1402       else
1403         {
1404           if (aop->aopu.aop_stk >= 0)
1405             offset += _G.stack.param_offset;
1406           tsprintf (s, "!*ixx", aop->aopu.aop_stk + offset);
1407         }
1408
1409       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1410
1411     case AOP_CRY:
1412       wassertl (0, "Tried to fetch from a bit variable");
1413
1414     case AOP_ACC:
1415       if (!offset)
1416         {
1417           return "a";
1418         }
1419       else
1420         {
1421           tsprintf(s, "!zero");
1422           return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1423         }
1424
1425     case AOP_HLREG:
1426       wassert (offset < 2);
1427       return aop->aopu.aop_str[offset];
1428
1429     case AOP_LIT:
1430       return aopLiteral (aop->aopu.aop_lit, offset);
1431
1432     case AOP_SIMPLELIT:
1433       {
1434         unsigned long v = aop->aopu.aop_simplelit;
1435         
1436         v >>= (offset * 8);
1437         tsprintf (s, "!immedbyte", (unsigned int) v & 0xff);
1438         
1439         return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1440       }
1441     case AOP_STR:
1442       aop->coff = offset;
1443       return aop->aopu.aop_str[offset];
1444
1445     case AOP_PAIRPTR:
1446       setupPair (aop->aopu.aop_pairId, aop, offset);
1447       sprintf (s, "(%s)", _pairs[aop->aopu.aop_pairId].name);
1448
1449       return traceAlloc(&_G.trace.aops, Safe_strdup(s));
1450
1451     default:
1452       break;
1453     }
1454   wassertl (0, "aopget got unsupported aop->type");
1455   exit (0);
1456 }
1457
1458 bool
1459 isRegString (const char *s)
1460 {
1461   if (!strcmp (s, "b") ||
1462       !strcmp (s, "c") ||
1463       !strcmp (s, "d") ||
1464       !strcmp (s, "e") ||
1465       !strcmp (s, "a") ||
1466       !strcmp (s, "h") ||
1467       !strcmp (s, "l"))
1468     return TRUE;
1469   return FALSE;
1470 }
1471
1472 bool
1473 isConstant (const char *s)
1474 {
1475   /* This is a bit of a hack... */
1476   return (*s == '#' || *s == '$');
1477 }
1478
1479 bool
1480 canAssignToPtr (const char *s)
1481 {
1482   if (isRegString (s))
1483     return TRUE;
1484   if (isConstant (s))
1485     return TRUE;
1486   return FALSE;
1487 }
1488
1489 /*-----------------------------------------------------------------*/
1490 /* aopPut - puts a string for a aop                                */
1491 /*-----------------------------------------------------------------*/
1492 static void
1493 aopPut (asmop * aop, const char *s, int offset)
1494 {
1495   char buffer2[256];
1496
1497   if (aop->size && offset > (aop->size - 1))
1498     {
1499       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1500               "aopPut got offset > aop->size");
1501       exit (0);
1502     }
1503
1504   // PENDING
1505   tsprintf(buffer2, s);
1506   s = buffer2;
1507
1508   /* will assign value to value */
1509   /* depending on where it is ofcourse */
1510   switch (aop->type)
1511     {
1512     case AOP_DIR:
1513       /* Direct.  Hmmm. */
1514       wassert (IS_GB);
1515       if (strcmp (s, "a"))
1516         emit2 ("ld a,%s", s);
1517       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
1518       break;
1519
1520     case AOP_SFR:
1521       wassert (IS_GB);
1522       if (strcmp (s, "a"))
1523         emit2 ("ld a,%s", s);
1524       emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
1525       break;
1526
1527     case AOP_REG:
1528       if (!strcmp (s, "!*hl"))
1529         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
1530       else
1531         emit2 ("ld %s,%s",
1532                aop->aopu.aop_reg[offset]->name, s);
1533       break;
1534
1535     case AOP_IY:
1536       wassert (!IS_GB);
1537       if (!canAssignToPtr (s))
1538         {
1539           emit2 ("ld a,%s", s);
1540           setupPair (PAIR_IY, aop, offset);
1541           emit2 ("ld !*iyx,a", offset);
1542         }
1543       else
1544         {
1545           setupPair (PAIR_IY, aop, offset);
1546           emit2 ("ld !*iyx,%s", offset, s);
1547         }
1548       break;
1549
1550     case AOP_HL:
1551       wassert (IS_GB);
1552       /* PENDING: for re-target */
1553       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1554         {
1555           emit2 ("ld a,!*hl");
1556           s = "a";
1557         }
1558       setupPair (PAIR_HL, aop, offset);
1559
1560       emit2 ("ld !*hl,%s", s);
1561       break;
1562
1563     case AOP_EXSTK:
1564       wassert (!IS_GB);
1565       if (!canAssignToPtr (s))
1566         {
1567           emit2 ("ld a,%s", s);
1568           setupPair (PAIR_IY, aop, offset);
1569           emit2 ("ld !*iyx,a", offset);
1570         }
1571       else
1572         {
1573           setupPair (PAIR_IY, aop, offset);
1574           emit2 ("ld !*iyx,%s", offset, s);
1575         }
1576       break;
1577
1578     case AOP_STK:
1579       if (IS_GB)
1580         {
1581           /* PENDING: re-target */
1582           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
1583             {
1584               emit2 ("ld a,!*hl");
1585               s = "a";
1586             }
1587           setupPair (PAIR_HL, aop, offset);
1588           if (!canAssignToPtr (s))
1589             {
1590               emit2 ("ld a,%s", s);
1591               emit2 ("ld !*hl,a");
1592             }
1593           else
1594             emit2 ("ld !*hl,%s", s);
1595         }
1596       else
1597         {
1598           if (aop->aopu.aop_stk >= 0)
1599             offset += _G.stack.param_offset;
1600           if (!canAssignToPtr (s))
1601             {
1602               emit2 ("ld a,%s", s);
1603               emit2 ("ld !*ixx,a", aop->aopu.aop_stk + offset);
1604             }
1605           else
1606             {
1607               emit2 ("ld !*ixx,%s", aop->aopu.aop_stk + offset, s);
1608             }
1609         }
1610       break;
1611
1612     case AOP_CRY:
1613       /* if bit variable */
1614       if (!aop->aopu.aop_dir)
1615         {
1616           emit2 ("ld a,#0");
1617           emit2 ("rla");
1618         }
1619       else
1620         {
1621           /* In bit space but not in C - cant happen */
1622           wassertl (0, "Tried to write into a bit variable");
1623         }
1624       break;
1625
1626     case AOP_STR:
1627       aop->coff = offset;
1628       if (strcmp (aop->aopu.aop_str[offset], s))
1629         {
1630           emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1631         }
1632       break;
1633
1634     case AOP_ACC:
1635       aop->coff = offset;
1636       if (!offset && (strcmp (s, "acc") == 0))
1637         break;
1638       if (offset > 0)
1639         {
1640           wassertl (0, "Tried to access past the end of A");
1641         }
1642       else
1643         {
1644           if (strcmp (aop->aopu.aop_str[offset], s))
1645             emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1646         }
1647       break;
1648
1649     case AOP_HLREG:
1650       wassert (offset < 2);
1651       emit2 ("ld %s,%s", aop->aopu.aop_str[offset], s);
1652       break;
1653
1654     case AOP_PAIRPTR:
1655       setupPair (aop->aopu.aop_pairId, aop, offset);
1656       emit2 ("ld (%s),%s", _pairs[aop->aopu.aop_pairId].name, s);
1657       break;
1658
1659     default:
1660       werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
1661               "aopPut got unsupported aop->type");
1662       exit (0);
1663     }
1664 }
1665
1666 #define AOP(op) op->aop
1667 #define AOP_TYPE(op) AOP(op)->type
1668 #define AOP_SIZE(op) AOP(op)->size
1669 #define AOP_NEEDSACC(x) (AOP(x) && (AOP_TYPE(x) == AOP_CRY))
1670
1671 static void
1672 commitPair (asmop * aop, PAIR_ID id)
1673 {
1674   /* PENDING: Verify this. */
1675   if (id == PAIR_HL && requiresHL (aop) && IS_GB)
1676     {
1677       emit2 ("ld a,l");
1678       emit2 ("ld d,h");
1679       aopPut (aop, "a", 0);
1680       aopPut (aop, "d", 1);
1681     }
1682   else
1683     {
1684       /* Special cases */
1685       if (id == PAIR_HL && aop->type == AOP_IY && aop->size == 2)
1686         {
1687           char *l = aopGetLitWordLong (aop, 0, FALSE);
1688           wassert (l);
1689
1690           emit2 ("ld (%s),%s", l, _pairs[id].name);
1691         }
1692       else
1693         {
1694           aopPut (aop, _pairs[id].l, 0);
1695           aopPut (aop, _pairs[id].h, 1);
1696         }
1697     }
1698 }
1699
1700 /*-----------------------------------------------------------------*/
1701 /* getDataSize - get the operand data size                         */
1702 /*-----------------------------------------------------------------*/
1703 int
1704 getDataSize (operand * op)
1705 {
1706   int size;
1707   size = AOP_SIZE (op);
1708   if (size == 3)
1709     {
1710       /* pointer */
1711       wassertl (0, "Somehow got a three byte data pointer");
1712     }
1713   return size;
1714 }
1715
1716 /*-----------------------------------------------------------------*/
1717 /* movLeft2Result - move byte from left to result                  */
1718 /*-----------------------------------------------------------------*/
1719 static void
1720 movLeft2Result (operand * left, int offl,
1721                 operand * result, int offr, int sign)
1722 {
1723   const char *l;
1724
1725   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
1726     {
1727       l = aopGet (AOP (left), offl, FALSE);
1728
1729       if (!sign)
1730         {
1731           aopPut (AOP (result), l, offr);
1732         }
1733       else
1734         {
1735           if (getDataSize (left) == offl + 1)
1736             {
1737               emit2 ("ld a,%s", l);
1738               aopPut (AOP (result), "a", offr);
1739             }
1740         }
1741     }
1742 }
1743
1744 static void
1745 movLeft2ResultLong (operand * left, int offl,
1746                 operand * result, int offr, int sign,
1747                 int size)
1748 {
1749   if (size == 1)
1750     {
1751       movLeft2Result (left, offl, result, offr, sign);
1752     }
1753   else
1754     {
1755       wassertl (offl == 0 && offr == 0, "Only implemented for zero offset");
1756       wassertl (size == 2, "Only implemented for two bytes or one");
1757
1758       if ( IS_GB && requiresHL ( AOP (left)) && getPairId ( AOP (result)) == PAIR_HL)
1759         {
1760           emit2 ("ld a,%s", aopGet (AOP (left), LSB, FALSE));
1761           emit2 ("ld h,%s", aopGet (AOP (left), MSB16, FALSE));
1762           emit2 ("ld l,a");
1763         }
1764       else if ( getPairId ( AOP (result)) == PAIR_IY)
1765         {
1766           PAIR_ID id = getPairId (AOP (left));
1767           if (id != PAIR_INVALID) 
1768             {
1769               emit2("push %s", _pairs[id].name);
1770               emit2("pop iy");
1771             }
1772           else
1773             {
1774               /* PENDING */
1775               emitDebug("Error");
1776             }
1777         }
1778       else
1779         {
1780           movLeft2Result (left, offl, result, offr, sign);
1781           movLeft2Result (left, offl+1, result, offr+1, sign);
1782         }
1783     }
1784 }
1785
1786 /** Put Acc into a register set
1787  */
1788 void
1789 outAcc (operand * result)
1790 {
1791   int size, offset;
1792   size = getDataSize (result);
1793   if (size)
1794     {
1795       aopPut (AOP (result), "a", 0);
1796       size--;
1797       offset = 1;
1798       /* unsigned or positive */
1799       while (size--)
1800         {
1801           aopPut (AOP (result), "!zero", offset++);
1802         }
1803     }
1804 }
1805
1806 /** Take the value in carry and put it into a register
1807  */
1808 void
1809 outBitCLong (operand * result, bool swap_sense)
1810 {
1811   /* if the result is bit */
1812   if (AOP_TYPE (result) == AOP_CRY)
1813     {
1814       wassertl (0, "Tried to write carry to a bit");
1815     }
1816   else
1817     {
1818       emit2 ("ld a,!zero");
1819       emit2 ("rla");
1820       if (swap_sense)
1821         emit2 ("xor a,!immedbyte", 1);
1822       outAcc (result);
1823     }
1824 }
1825
1826 void
1827 outBitC (operand * result)
1828 {
1829   outBitCLong (result, FALSE);
1830 }
1831
1832 /*-----------------------------------------------------------------*/
1833 /* toBoolean - emit code for orl a,operator(sizeop)                */
1834 /*-----------------------------------------------------------------*/
1835 void
1836 _toBoolean (operand * oper)
1837 {
1838   int size = AOP_SIZE (oper);
1839   int offset = 0;
1840   if (size > 1)
1841     {
1842       emit2 ("ld a,%s", aopGet (AOP (oper), offset++, FALSE));
1843       size--;
1844       while (size--)
1845         emit2 ("or a,%s", aopGet (AOP (oper), offset++, FALSE));
1846     }
1847   else
1848     {
1849       if (AOP (oper)->type != AOP_ACC)
1850         {
1851           _clearCarry();
1852           emit2 ("or a,%s", aopGet (AOP (oper), 0, FALSE));
1853         }
1854     }
1855 }
1856
1857 /*-----------------------------------------------------------------*/
1858 /* genNotFloat - generates not for float operations              */
1859 /*-----------------------------------------------------------------*/
1860 static void
1861 genNotFloat (operand * op, operand * res)
1862 {
1863   int size, offset;
1864   symbol *tlbl;
1865
1866   emitDebug ("; genNotFloat");
1867
1868   /* we will put 127 in the first byte of
1869      the result */
1870   aopPut (AOP (res), "!immedbyte", 0x7F);
1871   size = AOP_SIZE (op) - 1;
1872   offset = 1;
1873
1874   _moveA (aopGet (op->aop, offset++, FALSE));
1875
1876   while (size--)
1877     {
1878       emit2 ("or a,%s", aopGet (op->aop, offset++, FALSE));
1879     }
1880
1881   tlbl = newiTempLabel (NULL);
1882   aopPut (res->aop, "!one", 1);
1883   emit2 ("!shortjp z !tlabel", tlbl->key + 100);
1884   aopPut (res->aop, "!zero", 1);
1885
1886   emitLabel(tlbl->key + 100);
1887
1888   size = res->aop->size - 2;
1889   offset = 2;
1890   /* put zeros in the rest */
1891   while (size--)
1892     aopPut (res->aop, "!zero", offset++);
1893 }
1894
1895 /*-----------------------------------------------------------------*/
1896 /* genNot - generate code for ! operation                          */
1897 /*-----------------------------------------------------------------*/
1898 static void
1899 genNot (iCode * ic)
1900 {
1901   sym_link *optype = operandType (IC_LEFT (ic));
1902
1903   /* assign asmOps to operand & result */
1904   aopOp (IC_LEFT (ic), ic, FALSE, TRUE);
1905   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1906
1907   /* if in bit space then a special case */
1908   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1909     {
1910       wassertl (0, "Tried to negate a bit");
1911     }
1912
1913   /* if type float then do float */
1914   if (IS_FLOAT (optype))
1915     {
1916       genNotFloat (IC_LEFT (ic), IC_RESULT (ic));
1917       goto release;
1918     }
1919
1920   _toBoolean (IC_LEFT (ic));
1921
1922   /* Not of A:
1923      If A == 0, !A = 1
1924      else A = 0
1925      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
1926   emit2 ("sub a,!one");
1927   outBitC (IC_RESULT (ic));
1928
1929  release:
1930   /* release the aops */
1931   freeAsmop (IC_LEFT (ic), NULL, ic);
1932   freeAsmop (IC_RESULT (ic), NULL, ic);
1933 }
1934
1935 /*-----------------------------------------------------------------*/
1936 /* genCpl - generate code for complement                           */
1937 /*-----------------------------------------------------------------*/
1938 static void
1939 genCpl (iCode * ic)
1940 {
1941   int offset = 0;
1942   int size;
1943
1944
1945   /* assign asmOps to operand & result */
1946   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
1947   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
1948
1949   /* if both are in bit space then
1950      a special case */
1951   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
1952       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
1953     {
1954       wassertl (0, "Left and the result are in bit space");
1955     }
1956
1957   size = AOP_SIZE (IC_RESULT (ic));
1958   while (size--)
1959     {
1960       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
1961       _moveA (l);
1962       emit2("cpl");
1963       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
1964     }
1965
1966   /* release the aops */
1967   freeAsmop (IC_LEFT (ic), NULL, ic);
1968   freeAsmop (IC_RESULT (ic), NULL, ic);
1969 }
1970
1971 static void
1972 _gbz80_emitAddSubLongLong (iCode *ic, asmop *left, asmop *right, bool isAdd)
1973 {
1974   /* Logic:
1975        ld de,right.lw
1976        setup hl to left
1977        de = hl - de
1978        push flags
1979        store de into result
1980        pop flags
1981        ld de,right.hw
1982        setup hl
1983        de = hl -de
1984        store de into result
1985   */
1986   const char *first = isAdd ? "add" : "sub";
1987   const char *later = isAdd ? "adc" : "sbc";
1988
1989   wassertl (IS_GB, "Code is only relevent to the gbz80");
1990   wassertl (AOP( IC_RESULT (ic))->size == 4, "Only works for four bytes");
1991
1992   fetchPair (PAIR_DE, left);
1993
1994   emit2 ("ld a,e");
1995   emit2 ("%s a,%s", first, aopGet( right, LSB, FALSE));
1996   emit2 ("ld e,a");
1997   emit2 ("ld a,d");
1998   emit2 ("%s a,%s", later, aopGet( right, MSB16, FALSE));
1999
2000   _push (PAIR_AF);
2001   aopPut ( AOP (IC_RESULT (ic)), "a", MSB16);
2002   aopPut ( AOP (IC_RESULT (ic)), "e", LSB);
2003
2004   fetchPairLong (PAIR_DE, left, MSB24);
2005   aopGet (right, MSB24, FALSE);
2006
2007   _pop (PAIR_AF);
2008   emit2 ("ld a,e");
2009   emit2 ("%s a,%s", later, aopGet( right, MSB24, FALSE));
2010   emit2 ("ld e,a");
2011   emit2 ("ld a,d");
2012   emit2 ("%s a,%s", later, aopGet( right, MSB32, FALSE));
2013
2014   aopPut ( AOP (IC_RESULT (ic)), "a", MSB32);
2015   aopPut ( AOP (IC_RESULT (ic)), "e", MSB24);
2016 }
2017
2018 static void
2019 _gbz80_emitAddSubLong (iCode *ic, bool isAdd)
2020 {
2021   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
2022 }
2023
2024 /*-----------------------------------------------------------------*/
2025 /* genUminusFloat - unary minus for floating points                */
2026 /*-----------------------------------------------------------------*/
2027 static void
2028 genUminusFloat (operand * op, operand * result)
2029 {
2030   int size, offset = 0;
2031
2032   emitDebug("; genUminusFloat");
2033
2034   /* for this we just need to flip the
2035      first it then copy the rest in place */
2036   size = AOP_SIZE (op) - 1;
2037
2038   _moveA(aopGet (AOP (op), MSB32, FALSE));
2039
2040   emit2("xor a,!immedbyte", 0x80);
2041   aopPut (AOP (result), "a", MSB32);
2042
2043   while (size--)
2044     {
2045       aopPut (AOP (result), aopGet (AOP (op), offset, FALSE), offset);
2046       offset++;
2047     }
2048 }
2049
2050 /*-----------------------------------------------------------------*/
2051 /* genUminus - unary minus code generation                         */
2052 /*-----------------------------------------------------------------*/
2053 static void
2054 genUminus (iCode * ic)
2055 {
2056   int offset, size;
2057   sym_link *optype, *rtype;
2058
2059   /* assign asmops */
2060   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2061   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
2062
2063   /* if both in bit space then special
2064      case */
2065   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY &&
2066       AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
2067     {
2068       wassertl (0, "Left and right are in bit space");
2069       goto release;
2070     }
2071
2072   optype = operandType (IC_LEFT (ic));
2073   rtype = operandType (IC_RESULT (ic));
2074
2075   /* if float then do float stuff */
2076   if (IS_FLOAT (optype))
2077     {
2078       genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
2079       goto release;
2080     }
2081
2082   /* otherwise subtract from zero */
2083   size = AOP_SIZE (IC_LEFT (ic));
2084
2085   if (AOP_SIZE (IC_RESULT (ic)) == 4 && IS_GB)
2086     {
2087       /* Create a new asmop with value zero */
2088       asmop *azero = newAsmop (AOP_SIMPLELIT);
2089       azero->aopu.aop_simplelit = 0;
2090       azero->size = size;
2091       _gbz80_emitAddSubLongLong (ic, azero, AOP (IC_LEFT (ic)), FALSE);
2092       goto release;
2093     }
2094
2095   offset = 0;
2096   _clearCarry();
2097   while (size--)
2098     {
2099       const char *l = aopGet (AOP (IC_LEFT (ic)), offset, FALSE);
2100       emit2 ("ld a,!zero");
2101       emit2 ("sbc a,%s", l);
2102       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2103     }
2104
2105   /* if any remaining bytes in the result */
2106   /* we just need to propagate the sign   */
2107   if ((size = (AOP_SIZE (IC_RESULT (ic)) - AOP_SIZE (IC_LEFT (ic)))))
2108     {
2109       emit2 ("rlc a");
2110       emit2 ("sbc a,a");
2111       while (size--)
2112         aopPut (AOP (IC_RESULT (ic)), "a", offset++);
2113     }
2114
2115 release:
2116   /* release the aops */
2117   freeAsmop (IC_LEFT (ic), NULL, ic);
2118   freeAsmop (IC_RESULT (ic), NULL, ic);
2119 }
2120
2121 /*-----------------------------------------------------------------*/
2122 /* assignResultValue -               */
2123 /*-----------------------------------------------------------------*/
2124 void
2125 assignResultValue (operand * oper)
2126 {
2127   int size = AOP_SIZE (oper);
2128   bool topInA = 0;
2129
2130   wassertl (size <= 4, "Got a result that is bigger than four bytes");
2131   topInA = requiresHL (AOP (oper));
2132
2133   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
2134     {
2135       /* We do it the hard way here. */
2136       _push (PAIR_HL);
2137       aopPut (AOP (oper), _fReturn[0], 0);
2138       aopPut (AOP (oper), _fReturn[1], 1);
2139       _pop (PAIR_DE);
2140       aopPut (AOP (oper), _fReturn[0], 2);
2141       aopPut (AOP (oper), _fReturn[1], 3);
2142     }
2143   else
2144     {
2145       while (size--)
2146         {
2147           aopPut (AOP (oper), _fReturn[size], size);
2148         }
2149     }
2150 }
2151
2152 /** Simple restore that doesn't take into account what is used in the
2153     return.
2154 */
2155 static void
2156 _restoreRegsAfterCall(void)
2157 {
2158   if (_G.stack.pushedDE)
2159     {
2160       _pop ( PAIR_DE);
2161       _G.stack.pushedDE = FALSE;
2162     }
2163   if (_G.stack.pushedBC)
2164     {
2165       _pop ( PAIR_BC);
2166       _G.stack.pushedBC = FALSE;
2167     }
2168   _G.saves.saved = FALSE;
2169 }
2170
2171 static void
2172 _saveRegsForCall(iCode *ic, int sendSetSize)
2173 {
2174   /* Rules:
2175       o Stack parameters are pushed before this function enters
2176       o DE and BC may be used in this function.
2177       o HL and DE may be used to return the result.
2178       o HL and DE may be used to send variables.
2179       o DE and BC may be used to store the result value.
2180       o HL may be used in computing the sent value of DE
2181       o The iPushes for other parameters occur before any addSets
2182
2183      Logic: (to be run inside the first iPush or if none, before sending)
2184       o Compute if DE and/or BC are in use over the call
2185       o Compute if DE is used in the send set
2186       o Compute if DE and/or BC are used to hold the result value
2187       o If (DE is used, or in the send set) and is not used in the result, push.
2188       o If BC is used and is not in the result, push
2189       o 
2190       o If DE is used in the send set, fetch
2191       o If HL is used in the send set, fetch
2192       o Call
2193       o ...
2194   */
2195   if (_G.saves.saved == FALSE) {
2196     bool deInUse, bcInUse;
2197     bool deSending;
2198     bool bcInRet = FALSE, deInRet = FALSE;
2199     bitVect *rInUse;
2200
2201     rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), ic->rUsed);
2202
2203     deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue(rInUse, E_IDX);
2204     bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue(rInUse, C_IDX);
2205
2206     deSending = (sendSetSize > 1);
2207
2208     emitDebug ("; _saveRegsForCall: sendSetSize: %u deInUse: %u bcInUse: %u deSending: %u", sendSetSize, deInUse, bcInUse, deSending);
2209
2210     if (bcInUse && bcInRet == FALSE) {
2211       _push(PAIR_BC);
2212       _G.stack.pushedBC = TRUE;
2213     }
2214     if (deInUse && deInRet == FALSE) {
2215       _push(PAIR_DE);
2216       _G.stack.pushedDE = TRUE;
2217     }
2218
2219     _G.saves.saved = TRUE;
2220   }
2221   else {
2222     /* Already saved. */
2223   }
2224 }
2225
2226 /*-----------------------------------------------------------------*/
2227 /* genIpush - genrate code for pushing this gets a little complex  */
2228 /*-----------------------------------------------------------------*/
2229 static void
2230 genIpush (iCode * ic)
2231 {
2232   int size, offset = 0;
2233   const char *l;
2234
2235   /* if this is not a parm push : ie. it is spill push
2236      and spill push is always done on the local stack */
2237   if (!ic->parmPush)
2238     {
2239       wassertl(0, "Encountered an unsupported spill push.");
2240       return;
2241     }
2242
2243   if (_G.saves.saved == FALSE) {
2244     /* Caller saves, and this is the first iPush. */
2245     /* Scan ahead until we find the function that we are pushing parameters to.
2246        Count the number of addSets on the way to figure out what registers
2247        are used in the send set.
2248     */
2249     int nAddSets = 0;
2250     iCode *walk = ic->next;
2251     
2252     while (walk) {
2253       if (walk->op == SEND) {
2254         nAddSets++;
2255       }
2256       else if (walk->op == CALL || walk->op == PCALL) {
2257         /* Found it. */
2258         break;
2259       }
2260       else {
2261         /* Keep looking. */
2262       }
2263       walk = walk->next;
2264     }
2265     _saveRegsForCall(walk, nAddSets);
2266   }
2267   else {
2268     /* Already saved by another iPush. */
2269   }
2270
2271   /* then do the push */
2272   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2273
2274   size = AOP_SIZE (IC_LEFT (ic));
2275
2276   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
2277     {
2278       _G.stack.pushed += 2;
2279       emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
2280     }
2281   else
2282     {
2283       if (size == 2)
2284         {
2285           fetchHL (AOP (IC_LEFT (ic)));
2286           emit2 ("push hl");
2287           spillPair (PAIR_HL);
2288           _G.stack.pushed += 2;
2289           goto release;
2290         }
2291       if (size == 4)
2292         {
2293           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2294           emit2 ("push hl");
2295           spillPair (PAIR_HL);
2296           _G.stack.pushed += 2;
2297           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0);
2298           emit2 ("push hl");
2299           spillPair (PAIR_HL);
2300           _G.stack.pushed += 2;
2301           goto release;
2302         }
2303       offset = size;
2304       while (size--)
2305         {
2306           if (AOP (IC_LEFT (ic))->type == AOP_IY)
2307             {
2308               char *l = aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE);
2309               wassert (l);
2310               emit2 ("ld a,(%s)", l);
2311             }
2312           else
2313             {
2314               l = aopGet (AOP (IC_LEFT (ic)), --offset, FALSE);
2315               emit2 ("ld a,%s", l);
2316             }
2317           emit2 ("push af");
2318           emit2 ("inc sp");
2319           _G.stack.pushed++;
2320         }
2321     }
2322 release:
2323   freeAsmop (IC_LEFT (ic), NULL, ic);
2324 }
2325
2326 /*-----------------------------------------------------------------*/
2327 /* genIpop - recover the registers: can happen only for spilling   */
2328 /*-----------------------------------------------------------------*/
2329 static void
2330 genIpop (iCode * ic)
2331 {
2332   int size, offset;
2333
2334
2335   /* if the temp was not pushed then */
2336   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
2337     return;
2338
2339   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2340   size = AOP_SIZE (IC_LEFT (ic));
2341   offset = (size - 1);
2342   if (isPair (AOP (IC_LEFT (ic))))
2343     {
2344       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
2345     }
2346   else
2347     {
2348       while (size--)
2349         {
2350           emit2 ("dec sp");
2351           emit2 ("pop hl");
2352           spillPair (PAIR_HL);
2353           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
2354         }
2355     }
2356
2357   freeAsmop (IC_LEFT (ic), NULL, ic);
2358 }
2359
2360 /* This is quite unfortunate */
2361 static void
2362 setArea (int inHome)
2363 {
2364   /*
2365     static int lastArea = 0;
2366
2367      if (_G.in_home != inHome) {
2368      if (inHome) {
2369      const char *sz = port->mem.code_name;
2370      port->mem.code_name = "HOME";
2371      emit2("!area", CODE_NAME);
2372      port->mem.code_name = sz;
2373      }
2374      else
2375      emit2("!area", CODE_NAME); */
2376   _G.in_home = inHome;
2377   //    }
2378 }
2379
2380 static bool
2381 isInHome (void)
2382 {
2383   return _G.in_home;
2384 }
2385
2386 static int
2387 _opUsesPair (operand * op, iCode * ic, PAIR_ID pairId)
2388 {
2389   int ret = 0;
2390   asmop *aop;
2391   symbol *sym = OP_SYMBOL (op);
2392
2393   if (sym->isspilt || sym->nRegs == 0)
2394     return 0;
2395
2396   aopOp (op, ic, FALSE, FALSE);
2397
2398   aop = AOP (op);
2399   if (aop->type == AOP_REG)
2400     {
2401       int i;
2402       for (i = 0; i < aop->size; i++)
2403         {
2404           if (pairId == PAIR_DE)
2405             {
2406               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2407               if (!strcmp (aop->aopu.aop_reg[i]->name, "e"))
2408                 ret++;
2409               if (!strcmp (aop->aopu.aop_reg[i]->name, "d"))
2410                 ret++;
2411             }
2412           else if (pairId == PAIR_BC)
2413             {
2414               emitDebug ("; name %s", aop->aopu.aop_reg[i]->name);
2415               if (!strcmp (aop->aopu.aop_reg[i]->name, "c"))
2416                 ret++;
2417               if (!strcmp (aop->aopu.aop_reg[i]->name, "b"))
2418                 ret++;
2419             }
2420           else
2421             {
2422               wassert (0);
2423             }
2424         }
2425     }
2426
2427   freeAsmop (IC_LEFT (ic), NULL, ic);
2428   return ret;
2429 }
2430
2431 /** Emit the code for a call statement
2432  */
2433 static void
2434 emitCall (iCode * ic, bool ispcall)
2435 {
2436   sym_link *dtype = operandType (IC_LEFT (ic));
2437
2438   /* if caller saves & we have not saved then */
2439   if (!ic->regsSaved)
2440     {
2441       /* PENDING */
2442     }
2443
2444   _saveRegsForCall(ic, _G.sendSet ? elementsInSet(_G.sendSet) : 0);
2445
2446   /* if send set is not empty then assign */
2447   if (_G.sendSet)
2448     {
2449       iCode *sic;
2450       int send = 0;
2451       int nSend = elementsInSet(_G.sendSet);
2452       bool swapped = FALSE;
2453
2454       int _z80_sendOrder[] = {
2455         PAIR_BC, PAIR_DE
2456       };
2457
2458       if (nSend > 1) {
2459         /* Check if the parameters are swapped.  If so route through hl instead. */
2460         wassertl (nSend == 2, "Pedantic check.  Code only checks for the two send items case.");
2461
2462         sic = setFirstItem(_G.sendSet);
2463         sic = setNextItem(_G.sendSet);
2464
2465         if (_opUsesPair (IC_LEFT(sic), sic, _z80_sendOrder[0])) {
2466           /* The second send value is loaded from one the one that holds the first
2467              send, i.e. it is overwritten. */
2468           /* Cache the first in HL, and load the second from HL instead. */
2469           emit2 ("ld h,%s", _pairs[_z80_sendOrder[0]].h);
2470           emit2 ("ld l,%s", _pairs[_z80_sendOrder[0]].l);
2471
2472           swapped = TRUE;
2473         }
2474       }
2475
2476       for (sic = setFirstItem (_G.sendSet); sic;
2477            sic = setNextItem (_G.sendSet))
2478         {
2479           int size;
2480           aopOp (IC_LEFT (sic), sic, FALSE, FALSE);
2481
2482           size = AOP_SIZE (IC_LEFT (sic));
2483           wassertl (size <= 2, "Tried to send a parameter that is bigger than two bytes");
2484           wassertl (_z80_sendOrder[send] != PAIR_INVALID, "Tried to send more parameters than we have registers for");
2485
2486           // PENDING: Mild hack
2487           if (swapped == TRUE && send == 1) {
2488             if (size > 1) {
2489               emit2 ("ld %s,h", _pairs[_z80_sendOrder[send]].h);
2490             }
2491             else {
2492               emit2 ("ld %s,!zero", _pairs[_z80_sendOrder[send]].h);
2493             }
2494             emit2 ("ld %s,l", _pairs[_z80_sendOrder[send]].l);
2495           }
2496           else {
2497             fetchPair(_z80_sendOrder[send], AOP (IC_LEFT (sic)));
2498           }
2499
2500           send++;
2501           freeAsmop (IC_LEFT (sic), NULL, sic);
2502         }
2503       _G.sendSet = NULL;
2504     }
2505
2506   if (ispcall)
2507     {
2508       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2509         {
2510           werror (W_INDIR_BANKED);
2511         }
2512       aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2513
2514       if (isLitWord (AOP (IC_LEFT (ic))))
2515         {
2516           emit2 ("call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
2517         }
2518       else
2519         {
2520           symbol *rlbl = newiTempLabel (NULL);
2521           spillPair (PAIR_HL);
2522           emit2 ("ld hl,!immed!tlabel", (rlbl->key + 100));
2523           emit2 ("push hl");
2524           _G.stack.pushed += 2;
2525
2526           fetchHL (AOP (IC_LEFT (ic)));
2527           emit2 ("jp !*hl");
2528           emit2 ("!tlabeldef", (rlbl->key + 100));
2529           _G.stack.pushed -= 2;
2530         }
2531       freeAsmop (IC_LEFT (ic), NULL, ic);
2532     }
2533   else
2534     {
2535       char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ?
2536       OP_SYMBOL (IC_LEFT (ic))->rname :
2537       OP_SYMBOL (IC_LEFT (ic))->name;
2538       if (IFFUNC_ISBANKEDCALL (dtype) && !SPEC_STAT(getSpec(dtype)))
2539         {
2540           emit2 ("call banked_call");
2541           emit2 ("!dws", name);
2542           emit2 ("!dw !bankimmeds", name);
2543         }
2544       else
2545         {
2546           /* make the call */
2547           emit2 ("call %s", name);
2548         }
2549     }
2550   spillCached ();
2551
2552   /* Mark the regsiters as restored. */
2553   _G.saves.saved = FALSE;
2554
2555   /* if we need assign a result value */
2556   if ((IS_ITEMP (IC_RESULT (ic)) &&
2557        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
2558         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
2559       IS_TRUE_SYMOP (IC_RESULT (ic)))
2560     {
2561
2562       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
2563
2564       assignResultValue (IC_RESULT (ic));
2565
2566       freeAsmop (IC_RESULT (ic), NULL, ic);
2567     }
2568
2569   /* adjust the stack for parameters if required */
2570   if (ic->parmBytes)
2571     {
2572       int i = ic->parmBytes;
2573
2574       _G.stack.pushed -= i;
2575       if (IS_GB)
2576         {
2577           emit2 ("!ldaspsp", i);
2578         }
2579       else
2580         {
2581           spillCached ();
2582           if (i > 8)
2583             {
2584               emit2 ("ld iy,#%d", i);
2585               emit2 ("add iy,sp");
2586               emit2 ("ld sp,iy");
2587             }
2588           else
2589             {
2590               while (i > 1)
2591                 {
2592                   emit2 ("pop af");
2593                   i -= 2;
2594                 }
2595               if (i)
2596                 {
2597                   emit2 ("inc sp");
2598                 }
2599             }
2600         }
2601     }
2602
2603   spillCached ();
2604
2605   if (_G.stack.pushedDE) 
2606     {
2607       bool dInRet = bitVectBitValue(ic->rUsed, D_IDX);
2608       bool eInRet = bitVectBitValue(ic->rUsed, E_IDX);
2609
2610       if (dInRet && eInRet)
2611         {
2612           wassertl (0, "Shouldn't push DE if it's wiped out by the return");
2613         }
2614       else if (dInRet)
2615         {
2616           /* Only restore E */
2617           emit2 ("ld a,d");
2618           _pop (PAIR_DE);
2619           emit2 ("ld d,a");
2620         }
2621       else if (eInRet)
2622         {
2623           /* Only restore D */
2624           _pop (PAIR_AF);
2625           emit2 ("ld d,a");
2626         }
2627       else
2628         {
2629           _pop (PAIR_DE);
2630         }
2631       _G.stack.pushedDE = FALSE;
2632     }
2633   
2634   if (_G.stack.pushedBC) 
2635     {
2636       bool bInRet = bitVectBitValue(ic->rUsed, B_IDX);
2637       bool cInRet = bitVectBitValue(ic->rUsed, C_IDX);
2638
2639       if (bInRet && cInRet)
2640         {
2641           wassertl (0, "Shouldn't push BC if it's wiped out by the return");
2642         }
2643       else if (bInRet)
2644         {
2645           /* Only restore C */
2646           emit2 ("ld a,b");
2647           _pop (PAIR_BC);
2648           emit2 ("ld b,a");
2649         }
2650       else if (cInRet)
2651         {
2652           /* Only restore B */
2653           _pop (PAIR_AF);
2654           emit2 ("ld b,a");
2655         }
2656       else
2657         {
2658           _pop (PAIR_BC);
2659         }
2660       _G.stack.pushedBC = FALSE;
2661     }
2662 }
2663
2664 /*-----------------------------------------------------------------*/
2665 /* genCall - generates a call statement                            */
2666 /*-----------------------------------------------------------------*/
2667 static void
2668 genCall (iCode * ic)
2669 {
2670   emitCall (ic, FALSE);
2671 }
2672
2673 /*-----------------------------------------------------------------*/
2674 /* genPcall - generates a call by pointer statement                */
2675 /*-----------------------------------------------------------------*/
2676 static void
2677 genPcall (iCode * ic)
2678 {
2679   emitCall (ic, TRUE);
2680 }
2681
2682 /*-----------------------------------------------------------------*/
2683 /* resultRemat - result  is rematerializable                       */
2684 /*-----------------------------------------------------------------*/
2685 static int
2686 resultRemat (iCode * ic)
2687 {
2688   if (SKIP_IC (ic) || ic->op == IFX)
2689     return 0;
2690
2691   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
2692     {
2693       symbol *sym = OP_SYMBOL (IC_RESULT (ic));
2694       if (sym->remat && !POINTER_SET (ic))
2695         return 1;
2696     }
2697
2698   return 0;
2699 }
2700
2701 extern set *publics;
2702
2703 /*-----------------------------------------------------------------*/
2704 /* genFunction - generated code for function entry                 */
2705 /*-----------------------------------------------------------------*/
2706 static void
2707 genFunction (iCode * ic)
2708 {
2709   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2710   sym_link *ftype;
2711
2712 #if CALLEE_SAVES
2713   bool bcInUse = FALSE;
2714   bool deInUse = FALSE;
2715 #endif
2716
2717   setArea (IFFUNC_NONBANKED (sym->type));
2718
2719   /* PENDING: Reset the receive offset as it doesn't seem to get reset anywhere
2720      else.
2721   */
2722   _G.receiveOffset = 0;
2723
2724   /* Record the last function name for debugging. */
2725   _G.lastFunctionName = sym->rname;
2726   
2727   /* Create the function header */
2728   emit2 ("!functionheader", sym->name);
2729   /* PENDING: portability. */
2730   emit2 ("__%s_start:", sym->rname);
2731   emit2 ("!functionlabeldef", sym->rname);
2732
2733   if (options.profile) 
2734     {
2735       emit2 ("!profileenter");
2736     }
2737
2738   ftype = operandType (IC_LEFT (ic));
2739
2740   /* if critical function then turn interrupts off */
2741   if (IFFUNC_ISCRITICAL (ftype))
2742     emit2 ("!di");
2743
2744   /* if this is an interrupt service routine then save all potentially used registers. */
2745   if (IFFUNC_ISISR (sym->type))
2746     {
2747       emit2 ("!pusha");
2748     }
2749
2750   /* PENDING: callee-save etc */
2751
2752   _G.stack.param_offset = 0;
2753
2754 #if CALLEE_SAVES
2755   /* Detect which registers are used. */
2756   if (sym->regsUsed)
2757     {
2758       int i;
2759       for (i = 0; i < sym->regsUsed->size; i++)
2760         {
2761           if (bitVectBitValue (sym->regsUsed, i))
2762             {
2763               switch (i)
2764                 {
2765                 case C_IDX:
2766                 case B_IDX:
2767                   bcInUse = TRUE;
2768                   break;
2769                 case D_IDX:
2770                 case E_IDX:
2771                   if (IS_Z80) {
2772                     deInUse = TRUE;
2773                   }
2774                   else {
2775                     /* Other systems use DE as a temporary. */
2776                   }
2777                   break;
2778                 }
2779             }
2780         }
2781     }
2782
2783   if (bcInUse) 
2784     {
2785       emit2 ("push bc");
2786       _G.stack.param_offset += 2;
2787     }
2788
2789   _G.stack.pushedBC = bcInUse;
2790
2791   if (deInUse)
2792     {
2793       emit2 ("push de");
2794       _G.stack.param_offset += 2;
2795     }
2796
2797   _G.stack.pushedDE = deInUse;
2798 #endif
2799
2800   /* adjust the stack for the function */
2801   _G.stack.last = sym->stack;
2802
2803   if (sym->stack && IS_GB && sym->stack > -INT8MIN)
2804     emit2 ("!enterxl", sym->stack);
2805   else if (sym->stack)
2806     emit2 ("!enterx", sym->stack);
2807   else
2808     emit2 ("!enter");
2809   _G.stack.offset = sym->stack;
2810 }
2811
2812 /*-----------------------------------------------------------------*/
2813 /* genEndFunction - generates epilogue for functions               */
2814 /*-----------------------------------------------------------------*/
2815 static void
2816 genEndFunction (iCode * ic)
2817 {
2818   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
2819
2820   if (IFFUNC_ISISR (sym->type))
2821     {
2822       wassertl (0, "Tried to close an interrupt support function");
2823     }
2824   else
2825     {
2826       if (IFFUNC_ISCRITICAL (sym->type))
2827         emit2 ("!ei");
2828
2829       /* PENDING: calleeSave */
2830
2831       if (_G.stack.offset && IS_GB && _G.stack.offset > INT8MAX)
2832         {
2833           emit2 ("!leavexl", _G.stack.offset);
2834         }
2835       else if (_G.stack.offset)
2836         {
2837           emit2 ("!leavex", _G.stack.offset);
2838         }
2839       else
2840         {
2841           emit2 ("!leave");
2842         }
2843
2844 #if CALLEE_SAVES
2845       if (_G.stack.pushedDE) 
2846         {
2847           emit2 ("pop de");
2848           _G.stack.pushedDE = FALSE;
2849         }
2850
2851       if (_G.stack.pushedDE) 
2852         {
2853           emit2 ("pop bc");
2854           _G.stack.pushedDE = FALSE;
2855         }
2856 #endif
2857
2858       if (options.profile) 
2859         {
2860           emit2 ("!profileexit");
2861         }
2862
2863
2864       /* Both baned and non-banked just ret */
2865       emit2 ("ret");
2866
2867       /* PENDING: portability. */
2868       emit2 ("__%s_end:", sym->rname);
2869     }
2870   _G.flushStatics = 1;
2871   _G.stack.pushed = 0;
2872   _G.stack.offset = 0;
2873 }
2874
2875 /*-----------------------------------------------------------------*/
2876 /* genRet - generate code for return statement                     */
2877 /*-----------------------------------------------------------------*/
2878 static void
2879 genRet (iCode * ic)
2880 {
2881     const char *l;
2882   /* Errk.  This is a hack until I can figure out how
2883      to cause dehl to spill on a call */
2884   int size, offset = 0;
2885
2886   /* if we have no return value then
2887      just generate the "ret" */
2888   if (!IC_LEFT (ic))
2889     goto jumpret;
2890
2891   /* we have something to return then
2892      move the return value into place */
2893   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
2894   size = AOP_SIZE (IC_LEFT (ic));
2895
2896   if ((size == 2) && ((l = aopGetWord (AOP (IC_LEFT (ic)), 0))))
2897     {
2898       if (IS_GB)
2899         {
2900           emit2 ("ld de,%s", l);
2901         }
2902       else
2903         {
2904           emit2 ("ld hl,%s", l);
2905         }
2906     }
2907   else
2908     {
2909       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
2910         {
2911           fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
2912           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 2);
2913         }
2914       else
2915         {
2916           while (size--)
2917             {
2918               l = aopGet (AOP (IC_LEFT (ic)), offset,
2919                           FALSE);
2920               if (strcmp (_fReturn[offset], l))
2921                 emit2 ("ld %s,%s", _fReturn[offset++], l);
2922             }
2923         }
2924     }
2925   freeAsmop (IC_LEFT (ic), NULL, ic);
2926
2927 jumpret:
2928   /* generate a jump to the return label
2929      if the next is not the return statement */
2930   if (!(ic->next && ic->next->op == LABEL &&
2931         IC_LABEL (ic->next) == returnLabel))
2932
2933     emit2 ("jp !tlabel", returnLabel->key + 100);
2934 }
2935
2936 /*-----------------------------------------------------------------*/
2937 /* genLabel - generates a label                                    */
2938 /*-----------------------------------------------------------------*/
2939 static void
2940 genLabel (iCode * ic)
2941 {
2942   /* special case never generate */
2943   if (IC_LABEL (ic) == entryLabel)
2944     return;
2945
2946   emitLabel (IC_LABEL (ic)->key + 100);
2947 }
2948
2949 /*-----------------------------------------------------------------*/
2950 /* genGoto - generates a ljmp                                      */
2951 /*-----------------------------------------------------------------*/
2952 static void
2953 genGoto (iCode * ic)
2954 {
2955   emit2 ("jp !tlabel", IC_LABEL (ic)->key + 100);
2956 }
2957
2958 /*-----------------------------------------------------------------*/
2959 /* genPlusIncr :- does addition with increment if possible         */
2960 /*-----------------------------------------------------------------*/
2961 static bool
2962 genPlusIncr (iCode * ic)
2963 {
2964   unsigned int icount;
2965   unsigned int size = getDataSize (IC_RESULT (ic));
2966   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
2967
2968   /* will try to generate an increment */
2969   /* if the right side is not a literal
2970      we cannot */
2971   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
2972     return FALSE;
2973
2974   emitDebug ("; genPlusIncr");
2975
2976   icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
2977
2978   /* If result is a pair */
2979   if (resultId != PAIR_INVALID)
2980     {
2981       if (isLitWord (AOP (IC_LEFT (ic))))
2982         {
2983           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
2984           return TRUE;
2985         }
2986       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 2)
2987         {
2988           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
2989             {
2990               PAIR_ID freep = getFreePairId (ic);
2991               if (freep != PAIR_INVALID)
2992                 {
2993                   fetchPair (freep, AOP (IC_RIGHT (ic)));
2994                   emit2 ("add hl,%s", _pairs[freep].name);
2995                   return TRUE;
2996                 }
2997             }
2998           else
2999             {
3000               fetchPair (resultId, AOP (IC_RIGHT (ic)));
3001               emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3002               return TRUE;
3003             }
3004         }
3005       if (icount > 5)
3006         return FALSE;
3007       /* Inc a pair */
3008       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3009         {
3010           if (icount > 2)
3011             return FALSE;
3012           movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3013         }
3014       while (icount--)
3015         {
3016           emit2 ("inc %s", getPairName (AOP (IC_RESULT (ic))));
3017         }
3018       return TRUE;
3019     }
3020
3021   if (IS_Z80 && isLitWord (AOP (IC_LEFT (ic))) && size == 2)
3022     {
3023       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
3024       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3025       return TRUE;
3026     }
3027
3028   /* if the literal value of the right hand side
3029      is greater than 4 then it is not worth it */
3030   if (icount > 4)
3031     return FALSE;
3032
3033   /* if increment 16 bits in register */
3034   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3035       size > 1 &&
3036       icount == 1
3037     )
3038     {
3039       int offset = 0;
3040       symbol *tlbl = NULL;
3041       tlbl = newiTempLabel (NULL);
3042       while (size--)
3043         {
3044           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), offset++, FALSE));
3045           if (size)
3046             {
3047               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
3048             }
3049         }
3050       emitLabel (tlbl->key + 100);
3051       return TRUE;
3052     }
3053
3054   /* if the sizes are greater than 1 then we cannot */
3055   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3056       AOP_SIZE (IC_LEFT (ic)) > 1)
3057     return FALSE;
3058
3059   /* If the result is in a register then we can load then increment.
3060    */
3061   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
3062     {
3063       aopPut (AOP (IC_RESULT (ic)), aopGet (AOP (IC_LEFT (ic)), LSB, FALSE), LSB);
3064       while (icount--)
3065         {
3066           emit2 ("inc %s", aopGet (AOP (IC_RESULT (ic)), LSB, FALSE));
3067         }
3068       return TRUE;
3069     }
3070
3071   /* we can if the aops of the left & result match or
3072      if they are in registers and the registers are the
3073      same */
3074   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3075     {
3076       while (icount--)
3077         {
3078           emit2 ("inc %s", aopGet (AOP (IC_LEFT (ic)), 0, FALSE));
3079         }
3080       return TRUE;
3081     }
3082
3083   return FALSE;
3084 }
3085
3086 /*-----------------------------------------------------------------*/
3087 /* outBitAcc - output a bit in acc                                 */
3088 /*-----------------------------------------------------------------*/
3089 void
3090 outBitAcc (operand * result)
3091 {
3092   symbol *tlbl = newiTempLabel (NULL);
3093   /* if the result is a bit */
3094   if (AOP_TYPE (result) == AOP_CRY)
3095     {
3096       wassertl (0, "Tried to write A into a bit");
3097     }
3098   else
3099     {
3100       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
3101       emit2 ("ld a,!one");
3102       emitLabel (tlbl->key + 100);
3103       outAcc (result);
3104     }
3105 }
3106
3107 bool
3108 couldDestroyCarry (asmop *aop)
3109 {
3110   if (aop)
3111     {
3112       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
3113         {
3114           return TRUE;
3115         }
3116     }
3117   return FALSE;
3118 }
3119
3120 static void
3121 shiftIntoPair (int idx, asmop *aop)
3122 {
3123   PAIR_ID id = PAIR_INVALID;
3124
3125   wassertl (IS_Z80, "Only implemented for the Z80");
3126   //  wassertl (aop->type == AOP_EXSTK, "Only implemented for EXSTK");
3127
3128   switch (idx) 
3129     {
3130     case 0:
3131       id = PAIR_HL;
3132       break;
3133     case 1:
3134       id = PAIR_DE;
3135       _push (PAIR_DE);
3136       break;
3137     default:
3138       wassertl (0, "Internal error - hit default case");
3139     }
3140
3141   emitDebug ("; Shift into pair idx %u", idx);
3142
3143   if (id == PAIR_HL)
3144     {
3145       setupPair (PAIR_HL, aop, 0);
3146     }
3147   else
3148     {
3149       setupPair (PAIR_IY, aop, 0);
3150       emit2 ("push iy");
3151       emit2 ("pop %s", _pairs[id].name);
3152     }
3153
3154   aop->type = AOP_PAIRPTR;
3155   aop->aopu.aop_pairId = id;
3156   _G.pairs[id].offset = 0;
3157   _G.pairs[id].last_type = aop->type;
3158 }
3159
3160 static void 
3161 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
3162 {
3163   wassert (left && right);
3164
3165   if (IS_Z80)
3166     {
3167       if (couldDestroyCarry (right) && couldDestroyCarry (result))
3168         {
3169           shiftIntoPair (0, right);
3170           shiftIntoPair (1, result);
3171         }
3172       else if (couldDestroyCarry (right))
3173         {
3174           shiftIntoPair (0, right);
3175         }
3176       else if (couldDestroyCarry (result))
3177         {
3178           shiftIntoPair (0, result);
3179         }
3180       else
3181         {
3182           /* Fine */
3183         }
3184     }
3185 }
3186
3187 /*-----------------------------------------------------------------*/
3188 /* genPlus - generates code for addition                           */
3189 /*-----------------------------------------------------------------*/
3190 static void
3191 genPlus (iCode * ic)
3192 {
3193   int size, offset = 0;
3194
3195   /* special cases :- */
3196
3197   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3198   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3199   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3200
3201   /* Swap the left and right operands if:
3202
3203      if literal, literal on the right or
3204      if left requires ACC or right is already
3205      in ACC */
3206
3207   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) ||
3208       (AOP_NEEDSACC (IC_LEFT (ic))) ||
3209       AOP_TYPE (IC_RIGHT (ic)) == AOP_ACC)
3210     {
3211       operand *t = IC_RIGHT (ic);
3212       IC_RIGHT (ic) = IC_LEFT (ic);
3213       IC_LEFT (ic) = t;
3214     }
3215
3216   /* if both left & right are in bit
3217      space */
3218   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3219       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3220     {
3221       /* Cant happen */
3222       wassertl (0, "Tried to add two bits");
3223     }
3224
3225   /* if left in bit space & right literal */
3226   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3227       AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
3228     {
3229       /* Can happen I guess */
3230       wassertl (0, "Tried to add a bit to a literal");
3231     }
3232
3233   /* if I can do an increment instead
3234      of add then GOOD for ME */
3235   if (genPlusIncr (ic) == TRUE)
3236     goto release;
3237
3238   emitDebug ("; Can't optimise plus by inc, falling back to the normal way");
3239
3240   size = getDataSize (IC_RESULT (ic));
3241
3242   /* Special case when left and right are constant */
3243   if (isPair (AOP (IC_RESULT (ic))))
3244     {
3245       char *left, *right;
3246       left = aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE);
3247       right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
3248
3249       if (AOP_TYPE(IC_LEFT(ic)) == AOP_LIT && AOP_TYPE(IC_RIGHT(ic)) == AOP_LIT &&
3250           left && right)
3251         {
3252           /* It's a pair */
3253           /* PENDING: fix */
3254           char buffer[100];
3255           sprintf (buffer, "#(%s + %s)", left, right);
3256           emit2 ("ld %s,%s", getPairName (AOP (IC_RESULT (ic))), buffer);
3257           goto release;
3258         }
3259     }
3260
3261   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
3262     {
3263       /* Fetch into HL then do the add */
3264       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3265       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3266
3267       spillPair (PAIR_HL);
3268       
3269       if (left == PAIR_HL && right != PAIR_INVALID)
3270         {
3271           emit2 ("add hl,%s", _pairs[right].name);
3272           goto release;
3273         }
3274       else if (right == PAIR_HL && left != PAIR_INVALID)
3275         {
3276           emit2 ("add hl,%s", _pairs[left].name);
3277           goto release;
3278         }
3279       else if (right != PAIR_INVALID && right != PAIR_HL)
3280         {
3281           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3282           emit2 ("add hl,%s", getPairName (AOP (IC_RIGHT (ic))));
3283           goto release;
3284         }
3285       else if (left != PAIR_INVALID && left != PAIR_HL)
3286         { 
3287           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3288           emit2 ("add hl,%s", getPairName (AOP (IC_LEFT (ic))));
3289           goto release;
3290         }
3291       else
3292         {
3293           /* Can't do it */
3294         }
3295     }
3296
3297   if (isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL)
3298     {
3299       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
3300       emit2 ("add hl,%s ; 2", getPairName (AOP (IC_RIGHT (ic))));
3301       spillCached();
3302       commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3303       goto release;
3304     }
3305
3306   /* Special case:
3307      ld hl,sp+n trashes C so we cant afford to do it during an
3308      add with stack based varibles.  Worst case is:
3309      ld  hl,sp+left
3310      ld  a,(hl)
3311      ld  hl,sp+right
3312      add (hl)
3313      ld  hl,sp+result
3314      ld  (hl),a
3315      ld  hl,sp+left+1
3316      ld  a,(hl)
3317      ld  hl,sp+right+1
3318      adc (hl)
3319      ld  hl,sp+result+1
3320      ld  (hl),a
3321      So you cant afford to load up hl if either left, right, or result
3322      is on the stack (*sigh*)  The alt is:
3323      ld  hl,sp+left
3324      ld  de,(hl)
3325      ld  hl,sp+right
3326      ld  hl,(hl)
3327      add hl,de
3328      ld  hl,sp+result
3329      ld  (hl),hl
3330      Combinations in here are:
3331      * If left or right are in bc then the loss is small - trap later
3332      * If the result is in bc then the loss is also small
3333    */
3334   if (IS_GB)
3335     {
3336       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3337           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3338           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3339         {
3340           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3341                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3342               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3343                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3344             {
3345               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC)
3346                 {
3347                   /* Swap left and right */
3348                   operand *t = IC_RIGHT (ic);
3349                   IC_RIGHT (ic) = IC_LEFT (ic);
3350                   IC_LEFT (ic) = t;
3351                 }
3352               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
3353                 {
3354                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3355                   emit2 ("add hl,bc");
3356                 }
3357               else
3358                 {
3359                   fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3360                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
3361                   emit2 ("add hl,de");
3362                 }
3363               commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
3364               goto release;
3365             }
3366         }
3367       if (size == 4)
3368         {
3369           /* Be paranoid on the GB with 4 byte variables due to how C
3370              can be trashed by lda hl,n(sp).
3371           */
3372           _gbz80_emitAddSubLong (ic, TRUE);
3373           goto release;
3374         }
3375     }
3376
3377   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3378
3379   while (size--)
3380     {
3381       if (AOP_TYPE (IC_LEFT (ic)) == AOP_ACC)
3382         {
3383           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3384           if (offset == 0)
3385             emit2 ("add a,%s",
3386                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3387           else
3388             emit2 ("adc a,%s",
3389                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3390         }
3391       else
3392         {
3393           _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3394           if (offset == 0)
3395             emit2 ("add a,%s",
3396                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3397           else
3398             emit2 ("adc a,%s",
3399                    aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3400         }
3401       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3402     }
3403
3404 release:
3405   freeAsmop (IC_LEFT (ic), NULL, ic);
3406   freeAsmop (IC_RIGHT (ic), NULL, ic);
3407   freeAsmop (IC_RESULT (ic), NULL, ic);
3408
3409 }
3410
3411 /*-----------------------------------------------------------------*/
3412 /* genMinusDec :- does subtraction with deccrement if possible     */
3413 /*-----------------------------------------------------------------*/
3414 static bool
3415 genMinusDec (iCode * ic)
3416 {
3417   unsigned int icount;
3418   unsigned int size = getDataSize (IC_RESULT (ic));
3419
3420   /* will try to generate an increment */
3421   /* if the right side is not a literal we cannot */
3422   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3423     return FALSE;
3424
3425   /* if the literal value of the right hand side
3426      is greater than 4 then it is not worth it */
3427   if ((icount = (unsigned int) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) > 2)
3428     return FALSE;
3429
3430   size = getDataSize (IC_RESULT (ic));
3431
3432   /* if decrement 16 bits in register */
3433   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3434       (size > 1) && isPair (AOP (IC_RESULT (ic))))
3435     {
3436       while (icount--)
3437         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3438       return TRUE;
3439     }
3440
3441   /* If result is a pair */
3442   if (isPair (AOP (IC_RESULT (ic))))
3443     {
3444       movLeft2ResultLong (IC_LEFT (ic), 0, IC_RESULT (ic), 0, 0, 2);
3445       while (icount--)
3446         emit2 ("dec %s", getPairName (AOP (IC_RESULT (ic))));
3447       return TRUE;
3448     }
3449
3450   /* if increment 16 bits in register */
3451   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) &&
3452       (size == 2)
3453       )
3454     {
3455       fetchPair (_getTempPairId(), AOP (IC_RESULT (ic)));
3456
3457       while (icount--) {
3458         emit2 ("dec %s", _getTempPairName());
3459       }
3460
3461       commitPair (AOP (IC_RESULT (ic)), _getTempPairId());
3462
3463       return TRUE;
3464     }
3465
3466
3467   /* if the sizes are greater than 1 then we cannot */
3468   if (AOP_SIZE (IC_RESULT (ic)) > 1 ||
3469       AOP_SIZE (IC_LEFT (ic)) > 1)
3470     return FALSE;
3471
3472   /* we can if the aops of the left & result match or if they are in
3473      registers and the registers are the same */
3474   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
3475     {
3476       while (icount--)
3477         emit2 ("dec %s", aopGet (AOP (IC_RESULT (ic)), 0, FALSE));
3478       return TRUE;
3479     }
3480
3481   return FALSE;
3482 }
3483
3484 /*-----------------------------------------------------------------*/
3485 /* genMinus - generates code for subtraction                       */
3486 /*-----------------------------------------------------------------*/
3487 static void
3488 genMinus (iCode * ic)
3489 {
3490   int size, offset = 0;
3491   unsigned long lit = 0L;
3492
3493   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3494   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3495   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3496
3497   /* special cases :- */
3498   /* if both left & right are in bit space */
3499   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY &&
3500       AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
3501     {
3502       wassertl (0, "Tried to subtract two bits");
3503       goto release;
3504     }
3505
3506   /* if I can do an decrement instead of subtract then GOOD for ME */
3507   if (genMinusDec (ic) == TRUE)
3508     goto release;
3509
3510   size = getDataSize (IC_RESULT (ic));
3511
3512   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3513     {
3514     }
3515   else
3516     {
3517       lit = (unsigned long) floatFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
3518       lit = -(long) lit;
3519     }
3520
3521   /* Same logic as genPlus */
3522   if (IS_GB)
3523     {
3524       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK ||
3525           AOP_TYPE (IC_RIGHT (ic)) == AOP_STK ||
3526           AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
3527         {
3528           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
3529                AOP_SIZE (IC_RIGHT (ic)) == 2) &&
3530               (AOP_SIZE (IC_LEFT (ic)) <= 2 &&
3531                AOP_SIZE (IC_RIGHT (ic)) <= 2))
3532             {
3533               PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
3534               PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
3535
3536               if (left == PAIR_INVALID && right == PAIR_INVALID)
3537                 {
3538                   left = PAIR_DE;
3539                   right = PAIR_HL;
3540                 }
3541               else if (right == PAIR_INVALID)
3542                 right = PAIR_DE;
3543               else if (left == PAIR_INVALID)
3544                 left = PAIR_DE;
3545
3546               fetchPair (left, AOP (IC_LEFT (ic)));
3547               /* Order is important.  Right may be HL */
3548               fetchPair (right, AOP (IC_RIGHT (ic)));
3549
3550               emit2 ("ld a,%s", _pairs[left].l);
3551               emit2 ("sub a,%s", _pairs[right].l);
3552               emit2 ("ld e,a");
3553               emit2 ("ld a,%s", _pairs[left].h);
3554               emit2 ("sbc a,%s", _pairs[right].h);
3555
3556               if ( AOP_SIZE (IC_RESULT (ic)) > 1)
3557                 {
3558                   aopPut (AOP (IC_RESULT (ic)), "a", 1);
3559                 }
3560               aopPut (AOP (IC_RESULT (ic)), "e", 0);
3561               goto release;
3562             }
3563         }
3564       if (size == 4)
3565         {
3566           /* Be paranoid on the GB with 4 byte variables due to how C
3567              can be trashed by lda hl,n(sp).
3568           */
3569           _gbz80_emitAddSubLong (ic, FALSE);
3570           goto release;
3571         }
3572     }
3573
3574   setupToPreserveCarry (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
3575
3576   /* if literal, add a,#-lit, else normal subb */
3577   while (size--)
3578     {
3579       _moveA (aopGet (AOP (IC_LEFT (ic)), offset, FALSE));
3580       if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
3581         {
3582           if (!offset)
3583             emit2 ("sub a,%s",
3584                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3585           else
3586             emit2 ("sbc a,%s",
3587                       aopGet (AOP (IC_RIGHT (ic)), offset, FALSE));
3588         }
3589       else
3590         {
3591           /* first add without previous c */
3592           if (!offset)
3593             emit2 ("add a,!immedbyte", (unsigned int) (lit & 0x0FFL));
3594           else
3595             emit2 ("adc a,!immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
3596         }
3597       aopPut (AOP (IC_RESULT (ic)), "a", offset++);
3598     }
3599
3600   if (AOP_SIZE (IC_RESULT (ic)) == 3 &&
3601       AOP_SIZE (IC_LEFT (ic)) == 3 &&
3602       !sameRegs (AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic))))
3603     {
3604       wassertl (0, "Tried to subtract on a long pointer");
3605     }
3606
3607 release:
3608   freeAsmop (IC_LEFT (ic), NULL, ic);
3609   freeAsmop (IC_RIGHT (ic), NULL, ic);
3610   freeAsmop (IC_RESULT (ic), NULL, ic);
3611 }
3612
3613 /*-----------------------------------------------------------------*/
3614 /* genMult - generates code for multiplication                     */
3615 /*-----------------------------------------------------------------*/
3616 static void
3617 genMult (iCode * ic)
3618 {
3619   int val;
3620   int count, i;
3621   /* If true then the final operation should be a subtract */
3622   bool active = FALSE;
3623
3624   /* Shouldn't occur - all done through function calls */
3625   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
3626   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
3627   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
3628
3629   if (AOP_SIZE (IC_LEFT (ic)) > 2 ||
3630       AOP_SIZE (IC_RIGHT (ic)) > 2 ||
3631       AOP_SIZE (IC_RESULT (ic)) > 2)
3632     {
3633       wassertl (0, "Multiplication is handled through support function calls");
3634     }
3635
3636   /* Swap left and right such that right is a literal */
3637   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT))
3638     {
3639       operand *t = IC_RIGHT (ic);
3640       IC_RIGHT (ic) = IC_LEFT (ic);
3641       IC_LEFT (ic) = t;
3642     }
3643
3644   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal");
3645
3646   val = (int)floatFromVal ( AOP (IC_RIGHT (ic))->aopu.aop_lit);
3647   //  wassertl (val > 0, "Multiply must be positive");
3648   wassertl (val != 1, "Can't multiply by 1");
3649
3650   if (IS_Z80) {
3651     _push (PAIR_DE);
3652   }
3653
3654   if ( AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType ( IC_LEFT (ic)))))
3655     {
3656       emit2 ("ld e,%s", aopGet (AOP (IC_LEFT (ic)), LSB, FALSE));
3657       emit2 ("ld a,e");
3658       emit2 ("rlc a");
3659       emit2 ("sbc a,a");
3660       emit2 ("ld d,a");
3661     }
3662   else
3663     {
3664       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
3665     }
3666
3667   i = val;
3668
3669   /* Fully unroled version of mul.s.  Not the most efficient.
3670    */
3671   for (count = 0; count < 16; count++)
3672     {
3673       if (count != 0 && active)
3674         {
3675           emit2 ("add hl,hl");
3676         }
3677       if (i & 0x8000U)
3678         {
3679           if (active == FALSE)
3680             {
3681               emit2 ("ld l,e");
3682               emit2 ("ld h,d");
3683             }
3684           else
3685             {
3686               emit2 ("add hl,de");
3687             }
3688           active = TRUE;
3689         }
3690       i <<= 1;
3691     }
3692
3693   spillCached();
3694
3695   if (IS_Z80)
3696     {
3697       _pop (PAIR_DE);
3698     }
3699
3700   commitPair ( AOP (IC_RESULT (ic)), PAIR_HL);
3701
3702   freeAsmop (IC_LEFT (ic), NULL, ic);
3703   freeAsmop (IC_RIGHT (ic), NULL, ic);
3704   freeAsmop (IC_RESULT (ic), NULL, ic);
3705 }
3706
3707 /*-----------------------------------------------------------------*/
3708 /* genDiv - generates code for division                            */
3709 /*-----------------------------------------------------------------*/
3710 static void
3711 genDiv (iCode * ic)
3712 {
3713   /* Shouldn't occur - all done through function calls */
3714   wassertl (0, "Division is handled through support function calls");
3715 }
3716
3717 /*-----------------------------------------------------------------*/
3718 /* genMod - generates code for division                            */
3719 /*-----------------------------------------------------------------*/
3720 static void
3721 genMod (iCode * ic)
3722 {
3723   /* Shouldn't occur - all done through function calls */
3724   wassert (0);
3725 }
3726
3727 /*-----------------------------------------------------------------*/
3728 /* genIfxJump :- will create a jump depending on the ifx           */
3729 /*-----------------------------------------------------------------*/
3730 static void
3731 genIfxJump (iCode * ic, char *jval)
3732 {
3733   symbol *jlbl;
3734   const char *inst;
3735
3736   /* if true label then we jump if condition
3737      supplied is true */
3738   if (IC_TRUE (ic))
3739     {
3740       jlbl = IC_TRUE (ic);
3741       if (!strcmp (jval, "a"))
3742         {
3743           inst = "nz";
3744         }
3745       else if (!strcmp (jval, "c"))
3746         {
3747           inst = "c";
3748         }
3749       else if (!strcmp (jval, "nc"))
3750         {
3751           inst = "nc";
3752         }
3753       else if (!strcmp (jval, "m"))
3754         {
3755           inst = "m";
3756         }
3757       else if (!strcmp (jval, "p"))
3758         {
3759           inst = "p";
3760         }
3761       else
3762         {
3763           /* The buffer contains the bit on A that we should test */
3764           inst = "nz";
3765         }
3766     }
3767   else
3768     {
3769       /* false label is present */
3770       jlbl = IC_FALSE (ic);
3771       if (!strcmp (jval, "a"))
3772         {
3773           inst = "z";
3774         }
3775       else if (!strcmp (jval, "c"))
3776         {
3777           inst = "nc";
3778         }
3779       else if (!strcmp (jval, "nc"))
3780         {
3781           inst = "c";
3782         }
3783       else if (!strcmp (jval, "m"))
3784         {
3785           inst = "p";
3786         }
3787       else if (!strcmp (jval, "p"))
3788         {
3789           inst = "m";
3790         }
3791       else
3792         {
3793           /* The buffer contains the bit on A that we should test */
3794           inst = "z";
3795         }
3796     }
3797   /* Z80 can do a conditional long jump */
3798   if (!strcmp (jval, "a"))
3799     {
3800       emit2 ("or a,a");
3801     }
3802   else if (!strcmp (jval, "c"))
3803     {
3804     }
3805   else if (!strcmp (jval, "nc"))
3806     {
3807     }
3808   else if (!strcmp (jval, "m"))
3809     {
3810     }
3811   else if (!strcmp (jval, "p"))
3812     {
3813     }
3814   else
3815     {
3816       emit2 ("bit %s,a", jval);
3817     }
3818   emit2 ("jp %s,!tlabel", inst, jlbl->key + 100);
3819
3820   /* mark the icode as generated */
3821   ic->generated = 1;
3822 }
3823
3824 #if DISABLED
3825 static const char *
3826 _getPairIdName (PAIR_ID id)
3827 {
3828   return _pairs[id].name;
3829 }
3830 #endif
3831
3832 #if OLD
3833       /* if unsigned char cmp with lit, just compare */
3834       if ((size == 1) &&
3835           (AOP_TYPE (right) == AOP_LIT && AOP_TYPE (left) != AOP_DIR))
3836         {
3837           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
3838           if (sign)
3839             {
3840               emit2 ("xor a,!immedbyte", 0x80);
3841               emit2 ("cp %s^!constbyte", aopGet (AOP (right), offset, FALSE), 0x80);
3842             }
3843           else
3844             emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
3845         }
3846       else if (size == 4 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
3847         {
3848           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
3849           // Pull left into DE and right into HL
3850           aopGet (AOP(left), LSB, FALSE);
3851           emit2 ("ld d,h");
3852           emit2 ("ld e,l");
3853           aopGet (AOP(right), LSB, FALSE);
3854
3855           while (size--)
3856             {
3857               if (size == 0 && sign)
3858                 {
3859                   // Highest byte when signed needs the bits flipped
3860                   // Save the flags
3861                   emit2 ("push af");
3862                   emit2 ("ld a,(de)");
3863                   emit2 ("xor #0x80");
3864                   emit2 ("ld e,a");
3865                   emit2 ("ld a,(hl)");
3866                   emit2 ("xor #0x80");
3867                   emit2 ("ld d,a");
3868                   emit2 ("pop af");
3869                   emit2 ("ld a,e");
3870                   emit2 ("%s a,d", offset == 0 ? "sub" : "sbc");
3871                 }
3872               else
3873                 {
3874                   emit2 ("ld a,(de)");
3875                   emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
3876                 }
3877               
3878               if (size != 0)
3879                 {
3880                   emit2 ("inc hl");
3881                   emit2 ("inc de");
3882                 }
3883               offset++;
3884             }
3885           spillPair (PAIR_HL);
3886         }
3887       else if (size == 4 && IS_Z80 && couldDestroyCarry(AOP(right)) && couldDestroyCarry(AOP(left)))
3888         {
3889           setupPair (PAIR_HL, AOP (left), 0);
3890           aopGet (AOP(right), LSB, FALSE);
3891
3892           while (size--)
3893             {
3894               if (size == 0 && sign)
3895                 {
3896                   // Highest byte when signed needs the bits flipped
3897                   // Save the flags
3898                   emit2 ("push af");
3899                   emit2 ("ld a,(hl)");
3900                   emit2 ("xor #0x80");
3901                   emit2 ("ld l,a");
3902                   emit2 ("ld a,%d(iy)", offset);
3903                   emit2 ("xor #0x80");
3904                   emit2 ("ld h,a");
3905                   emit2 ("pop af");
3906                   emit2 ("ld a,l");
3907                   emit2 ("%s a,h", offset == 0 ? "sub" : "sbc");
3908                 }
3909               else
3910                 {
3911                   emit2 ("ld a,(hl)");
3912                   emit2 ("%s a,%d(iy)", offset == 0 ? "sub" : "sbc", offset);
3913                 }
3914               
3915               if (size != 0)
3916                 {
3917                   emit2 ("inc hl");
3918                 }
3919               offset++;
3920             }
3921           spillPair (PAIR_HL);
3922           spillPair (PAIR_IY);
3923         }
3924       else
3925         {
3926           if (AOP_TYPE (right) == AOP_LIT)
3927             {
3928               lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
3929               /* optimize if(x < 0) or if(x >= 0) */
3930               if (lit == 0L)
3931                 {
3932                   if (!sign)
3933                     {
3934                       /* No sign so it's always false */
3935                       _clearCarry();
3936                     }
3937                   else
3938                     {
3939                       /* Just load in the top most bit */
3940                       _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
3941                       if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
3942                         {
3943                           genIfxJump (ifx, "7");
3944                           return;
3945                         }
3946                       else
3947                         emit2 ("rlc a");
3948                     }
3949                   goto release;
3950                 }
3951             }
3952           
3953           if (sign)
3954             {
3955               /* First setup h and l contaning the top most bytes XORed */
3956               bool fDidXor = FALSE;
3957               if (AOP_TYPE (left) == AOP_LIT)
3958                 {
3959                   unsigned long lit = (unsigned long)
3960                   floatFromVal (AOP (left)->aopu.aop_lit);
3961                   emit2 ("ld %s,!immedbyte", _fTmp[0],
3962                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3963                 }
3964               else
3965                 {
3966                   emit2 ("ld a,%s", aopGet (AOP (left), size - 1, FALSE));
3967                   emit2 ("xor a,!immedbyte", 0x80);
3968                   emit2 ("ld %s,a", _fTmp[0]);
3969                   fDidXor = TRUE;
3970                 }
3971               if (AOP_TYPE (right) == AOP_LIT)
3972                 {
3973                   unsigned long lit = (unsigned long)
3974                   floatFromVal (AOP (right)->aopu.aop_lit);
3975                   emit2 ("ld %s,!immedbyte", _fTmp[1],
3976                          0x80 ^ (unsigned int) ((lit >> ((size - 1) * 8)) & 0x0FFL));
3977                 }
3978               else
3979                 {
3980                   emit2 ("ld a,%s", aopGet (AOP (right), size - 1, FALSE));
3981                   emit2 ("xor a,!immedbyte", 0x80);
3982                   emit2 ("ld %s,a", _fTmp[1]);
3983                   fDidXor = TRUE;
3984                 }
3985             }
3986           while (size--)
3987             {
3988               /* Do a long subtract */
3989               if (!sign || size)
3990                 {
3991                   _moveA (aopGet (AOP (left), offset, FALSE));
3992                 }
3993               if (sign && size == 0)
3994                 {
3995                   emit2 ("ld a,%s", _fTmp[0]);
3996                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", _fTmp[1]);
3997                 }
3998               else
3999                 {
4000                   /* Subtract through, propagating the carry */
4001                   emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4002                   offset++;
4003                 }
4004             }
4005         }
4006     }
4007 #endif
4008
4009 /** Generic compare for > or <
4010  */
4011 static void
4012 genCmp (operand * left, operand * right,
4013         operand * result, iCode * ifx, int sign)
4014 {
4015   int size, offset = 0;
4016   unsigned long lit = 0L;
4017   bool swap_sense = FALSE;
4018
4019   /* if left & right are bit variables */
4020   if (AOP_TYPE (left) == AOP_CRY &&
4021       AOP_TYPE (right) == AOP_CRY)
4022     {
4023       /* Cant happen on the Z80 */
4024       wassertl (0, "Tried to compare two bits");
4025     }
4026   else
4027     {
4028       /* Do a long subtract of right from left. */
4029       size = max (AOP_SIZE (left), AOP_SIZE (right));
4030
4031       if (size > 1 && IS_GB && requiresHL(AOP(right)) && requiresHL(AOP(left)))
4032         {
4033           // On the Gameboy we can't afford to adjust HL as it may trash the carry.
4034           // Pull left into DE and right into HL
4035           aopGet (AOP(left), LSB, FALSE);
4036           emit2 ("ld d,h");
4037           emit2 ("ld e,l");
4038           aopGet (AOP(right), LSB, FALSE);
4039
4040           while (size--)
4041             {
4042               emit2 ("ld a,(de)");
4043               emit2 ("%s a,(hl)", offset == 0 ? "sub" : "sbc");
4044               
4045               if (size != 0)
4046                 {
4047                   emit2 ("inc hl");
4048                   emit2 ("inc de");
4049                 }
4050               offset++;
4051             }
4052           spillPair (PAIR_HL);
4053           goto release;
4054         }
4055
4056       if (AOP_TYPE (right) == AOP_LIT)
4057         {
4058           lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4059           /* optimize if(x < 0) or if(x >= 0) */
4060           if (lit == 0)
4061             {
4062               if (!sign)
4063                 {
4064                   /* No sign so it's always false */
4065                   _clearCarry();
4066                 }
4067               else
4068                 {
4069                   /* Just load in the top most bit */
4070                   _moveA (aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
4071                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
4072                     {
4073                       genIfxJump (ifx, "7");
4074                       return;
4075                     }
4076                   else
4077                     {
4078                       if (!sign) 
4079                         {
4080                           emit2 ("rlc a");
4081                         }
4082                       if (ifx)
4083                         {
4084                           genIfxJump (ifx, swap_sense ? "c" : "nc");
4085                           return;
4086                         }
4087                     }
4088                 }
4089               goto release;
4090             }
4091         }
4092
4093       while (size--)
4094         {
4095           _moveA (aopGet (AOP (left), offset, FALSE));
4096           /* Subtract through, propagating the carry */
4097           emit2 ("%s a,%s", offset == 0 ? "sub" : "sbc", aopGet (AOP (right), offset, FALSE));
4098           offset++;
4099         }
4100     }
4101
4102 release:
4103   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4104     {
4105       if (sign)
4106         {
4107           /* Shift the sign bit up into carry */
4108           emit2 ("rlca");
4109         }
4110       outBitCLong (result, swap_sense);
4111     }
4112   else
4113     {
4114       /* if the result is used in the next
4115          ifx conditional branch then generate
4116          code a little differently */
4117       if (ifx)
4118         {
4119           if (sign)
4120             {
4121               if (IS_GB)
4122                 {
4123                   emit2 ("rlca");
4124                   genIfxJump (ifx, swap_sense ? "nc" : "c");
4125                 }
4126               else
4127                 {
4128                   genIfxJump (ifx, swap_sense ? "p" : "m");
4129                 }
4130             }
4131           else
4132             {
4133               genIfxJump (ifx, swap_sense ? "nc" : "c");
4134             }
4135         }
4136       else
4137         {
4138           if (sign)
4139             {
4140               /* Shift the sign bit up into carry */
4141               emit2 ("rlca");
4142             }
4143           outBitCLong (result, swap_sense);
4144         }
4145       /* leave the result in acc */
4146     }
4147 }
4148
4149 /*-----------------------------------------------------------------*/
4150 /* genCmpGt :- greater than comparison                             */
4151 /*-----------------------------------------------------------------*/
4152 static void
4153 genCmpGt (iCode * ic, iCode * ifx)
4154 {
4155   operand *left, *right, *result;
4156   sym_link *letype, *retype;
4157   int sign;
4158
4159   left = IC_LEFT (ic);
4160   right = IC_RIGHT (ic);
4161   result = IC_RESULT (ic);
4162
4163   letype = getSpec (operandType (left));
4164   retype = getSpec (operandType (right));
4165   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4166   /* assign the amsops */
4167   aopOp (left, ic, FALSE, FALSE);
4168   aopOp (right, ic, FALSE, FALSE);
4169   aopOp (result, ic, TRUE, FALSE);
4170
4171   genCmp (right, left, result, ifx, sign);
4172
4173   freeAsmop (left, NULL, ic);
4174   freeAsmop (right, NULL, ic);
4175   freeAsmop (result, NULL, ic);
4176 }
4177
4178 /*-----------------------------------------------------------------*/
4179 /* genCmpLt - less than comparisons                                */
4180 /*-----------------------------------------------------------------*/
4181 static void
4182 genCmpLt (iCode * ic, iCode * ifx)
4183 {
4184   operand *left, *right, *result;
4185   sym_link *letype, *retype;
4186   int sign;
4187
4188   left = IC_LEFT (ic);
4189   right = IC_RIGHT (ic);
4190   result = IC_RESULT (ic);
4191
4192   letype = getSpec (operandType (left));
4193   retype = getSpec (operandType (right));
4194   sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
4195
4196   /* assign the amsops */
4197   aopOp (left, ic, FALSE, FALSE);
4198   aopOp (right, ic, FALSE, FALSE);
4199   aopOp (result, ic, TRUE, FALSE);
4200
4201   genCmp (left, right, result, ifx, sign);
4202
4203   freeAsmop (left, NULL, ic);
4204   freeAsmop (right, NULL, ic);
4205   freeAsmop (result, NULL, ic);
4206 }
4207
4208 /*-----------------------------------------------------------------*/
4209 /* gencjneshort - compare and jump if not equal                    */
4210 /*-----------------------------------------------------------------*/
4211 static void
4212 gencjneshort (operand * left, operand * right, symbol * lbl)
4213 {
4214   int size = max (AOP_SIZE (left), AOP_SIZE (right));
4215   int offset = 0;
4216   unsigned long lit = 0L;
4217
4218   /* Swap the left and right if it makes the computation easier */
4219   if (AOP_TYPE (left) == AOP_LIT)
4220     {
4221       operand *t = right;
4222       right = left;
4223       left = t;
4224     }
4225
4226   if (AOP_TYPE (right) == AOP_LIT)
4227     {
4228       lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4229     }
4230
4231   /* if the right side is a literal then anything goes */
4232   if (AOP_TYPE (right) == AOP_LIT &&
4233       AOP_TYPE (left) != AOP_DIR)
4234     {
4235       if (lit == 0)
4236         {
4237           emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4238           if (size > 1)
4239             {
4240               while (--size)
4241                 {
4242                   emit2 ("or a,%s", aopGet (AOP (left), ++offset, FALSE));
4243                 }
4244             }
4245           else
4246             {
4247               emit2 ("or a,a");
4248             }
4249           emit2 ("jp nz,!tlabel", lbl->key + 100);
4250         }
4251       else
4252         {
4253           while (size--)
4254             {
4255               emit2 ("ld a,%s", aopGet (AOP (left), offset, FALSE));
4256               if ((AOP_TYPE (right) == AOP_LIT) && lit == 0)
4257                 emit2 ("or a,a");
4258               else
4259                 emit2 ("cp a,%s", aopGet (AOP (right), offset, FALSE));
4260               emit2 ("jp nz,!tlabel", lbl->key + 100);
4261               offset++;
4262             }
4263         }
4264     }
4265   /* if the right side is in a register or in direct space or
4266      if the left is a pointer register & right is not */
4267   else if (AOP_TYPE (right) == AOP_REG ||
4268            AOP_TYPE (right) == AOP_DIR ||
4269            (AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT))
4270     {
4271       while (size--)
4272         {
4273           _moveA (aopGet (AOP (left), offset, FALSE));
4274           if ((AOP_TYPE (left) == AOP_DIR && AOP_TYPE (right) == AOP_LIT) &&
4275               ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0))
4276             /* PENDING */
4277             emit2 ("jp nz,!tlabel", lbl->key + 100);
4278           else
4279             {
4280               emit2 ("cp %s", aopGet (AOP (right), offset, FALSE));
4281               emit2 ("jp nz,!tlabel", lbl->key + 100);
4282             }
4283           offset++;
4284         }
4285     }
4286   else
4287     {
4288       /* right is a pointer reg need both a & b */
4289       /* PENDING: is this required? */
4290       while (size--)
4291         {
4292           _moveA (aopGet (AOP (right), offset, FALSE));
4293           emit2 ("cp %s", aopGet (AOP (left), offset, FALSE));
4294           emit2 ("!shortjp nz,!tlabel", lbl->key + 100);
4295           offset++;
4296         }
4297     }
4298 }
4299
4300 /*-----------------------------------------------------------------*/
4301 /* gencjne - compare and jump if not equal                         */
4302 /*-----------------------------------------------------------------*/
4303 static void
4304 gencjne (operand * left, operand * right, symbol * lbl)
4305 {
4306   symbol *tlbl = newiTempLabel (NULL);
4307
4308   gencjneshort (left, right, lbl);
4309
4310   /* PENDING: ?? */
4311   emit2 ("ld a,!one");
4312   emit2 ("!shortjp !tlabel", tlbl->key + 100);
4313   emitLabel (lbl->key + 100);
4314   emit2 ("xor a,a");
4315   emitLabel (tlbl->key + 100);
4316 }
4317
4318 /*-----------------------------------------------------------------*/
4319 /* genCmpEq - generates code for equal to                          */
4320 /*-----------------------------------------------------------------*/
4321 static void
4322 genCmpEq (iCode * ic, iCode * ifx)
4323 {
4324   operand *left, *right, *result;
4325
4326   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4327   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4328   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4329
4330   emitDebug ("; genCmpEq: left %u, right %u, result %u", AOP_SIZE(IC_LEFT(ic)), AOP_SIZE(IC_RIGHT(ic)), AOP_SIZE(IC_RESULT(ic)));
4331
4332   /* Swap operands if it makes the operation easier. ie if:
4333      1.  Left is a literal.
4334    */
4335   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
4336     {
4337       operand *t = IC_RIGHT (ic);
4338       IC_RIGHT (ic) = IC_LEFT (ic);
4339       IC_LEFT (ic) = t;
4340     }
4341
4342   if (ifx && !AOP_SIZE (result))
4343     {
4344       symbol *tlbl;
4345       /* if they are both bit variables */
4346       if (AOP_TYPE (left) == AOP_CRY &&
4347           ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4348         {
4349           wassertl (0, "Tried to compare two bits");
4350         }
4351       else
4352         {
4353           tlbl = newiTempLabel (NULL);
4354           gencjneshort (left, right, tlbl);
4355           if (IC_TRUE (ifx))
4356             {
4357               emit2 ("jp !tlabel", IC_TRUE (ifx)->key + 100);
4358               emitLabel (tlbl->key + 100);
4359             }
4360           else
4361             {
4362               /* PENDING: do this better */
4363               symbol *lbl = newiTempLabel (NULL);
4364               emit2 ("!shortjp !tlabel", lbl->key + 100);
4365               emitLabel (tlbl->key + 100);
4366               emit2 ("jp !tlabel", IC_FALSE (ifx)->key + 100);
4367               emitLabel (lbl->key + 100);
4368             }
4369         }
4370       /* mark the icode as generated */
4371       ifx->generated = 1;
4372       goto release;
4373     }
4374
4375   /* if they are both bit variables */
4376   if (AOP_TYPE (left) == AOP_CRY &&
4377       ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
4378     {
4379       wassertl (0, "Tried to compare a bit to either a literal or another bit");
4380     }
4381   else
4382     {
4383       emitDebug(";4");
4384       
4385       gencjne (left, right, newiTempLabel (NULL));
4386       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
4387         {
4388           wassert (0);
4389         }
4390       if (ifx)
4391         {
4392           emitDebug(";5");
4393           genIfxJump (ifx, "a");
4394           goto release;
4395         }
4396       /* if the result is used in an arithmetic operation
4397          then put the result in place */
4398       if (AOP_TYPE (result) != AOP_CRY)
4399         {
4400           emitDebug(";6");
4401           outAcc (result);
4402         }
4403       /* leave the result in acc */
4404     }
4405
4406 release:
4407   freeAsmop (left, NULL, ic);
4408   freeAsmop (right, NULL, ic);
4409   freeAsmop (result, NULL, ic);
4410 }
4411
4412 /*-----------------------------------------------------------------*/
4413 /* ifxForOp - returns the icode containing the ifx for operand     */
4414 /*-----------------------------------------------------------------*/
4415 static iCode *
4416 ifxForOp (operand * op, iCode * ic)
4417 {
4418   /* if true symbol then needs to be assigned */
4419   if (IS_TRUE_SYMOP (op))
4420     return NULL;
4421
4422   /* if this has register type condition and
4423      the next instruction is ifx with the same operand
4424      and live to of the operand is upto the ifx only then */
4425   if (ic->next &&
4426       ic->next->op == IFX &&
4427       IC_COND (ic->next)->key == op->key &&
4428       OP_SYMBOL (op)->liveTo <= ic->next->seq)
4429     return ic->next;
4430
4431   return NULL;
4432 }
4433
4434 /*-----------------------------------------------------------------*/
4435 /* genAndOp - for && operation                                     */
4436 /*-----------------------------------------------------------------*/
4437 static void
4438 genAndOp (iCode * ic)
4439 {
4440   operand *left, *right, *result;
4441   symbol *tlbl;
4442
4443   /* note here that && operations that are in an if statement are
4444      taken away by backPatchLabels only those used in arthmetic
4445      operations remain */
4446   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4447   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4448   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4449
4450   /* if both are bit variables */
4451   if (AOP_TYPE (left) == AOP_CRY &&
4452       AOP_TYPE (right) == AOP_CRY)
4453     {
4454       wassertl (0, "Tried to and two bits");
4455     }
4456   else
4457     {
4458       tlbl = newiTempLabel (NULL);
4459       _toBoolean (left);
4460       emit2 ("!shortjp z,!tlabel", tlbl->key + 100);
4461       _toBoolean (right);
4462       emitLabel (tlbl->key + 100);
4463       outBitAcc (result);
4464     }
4465
4466   freeAsmop (left, NULL, ic);
4467   freeAsmop (right, NULL, ic);
4468   freeAsmop (result, NULL, ic);
4469 }
4470
4471 /*-----------------------------------------------------------------*/
4472 /* genOrOp - for || operation                                      */
4473 /*-----------------------------------------------------------------*/
4474 static void
4475 genOrOp (iCode * ic)
4476 {
4477   operand *left, *right, *result;
4478   symbol *tlbl;
4479
4480   /* note here that || operations that are in an
4481      if statement are taken away by backPatchLabels
4482      only those used in arthmetic operations remain */
4483   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
4484   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
4485   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
4486
4487   /* if both are bit variables */
4488   if (AOP_TYPE (left) == AOP_CRY &&
4489       AOP_TYPE (right) == AOP_CRY)
4490     {
4491       wassertl (0, "Tried to OR two bits");
4492     }
4493   else
4494     {
4495       tlbl = newiTempLabel (NULL);
4496       _toBoolean (left);
4497       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4498       _toBoolean (right);
4499       emitLabel (tlbl->key + 100);
4500       outBitAcc (result);
4501     }
4502
4503   freeAsmop (left, NULL, ic);
4504   freeAsmop (right, NULL, ic);
4505   freeAsmop (result, NULL, ic);
4506 }
4507
4508 /*-----------------------------------------------------------------*/
4509 /* isLiteralBit - test if lit == 2^n                               */
4510 /*-----------------------------------------------------------------*/
4511 int
4512 isLiteralBit (unsigned long lit)
4513 {
4514   unsigned long pw[32] =
4515   {1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
4516    0x100L, 0x200L, 0x400L, 0x800L,
4517    0x1000L, 0x2000L, 0x4000L, 0x8000L,
4518    0x10000L, 0x20000L, 0x40000L, 0x80000L,
4519    0x100000L, 0x200000L, 0x400000L, 0x800000L,
4520    0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
4521    0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L};
4522   int idx;
4523
4524   for (idx = 0; idx < 32; idx++)
4525     if (lit == pw[idx])
4526       return idx + 1;
4527   return 0;
4528 }
4529
4530 /*-----------------------------------------------------------------*/
4531 /* jmpTrueOrFalse -                                                */
4532 /*-----------------------------------------------------------------*/
4533 static void
4534 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
4535 {
4536   // ugly but optimized by peephole
4537   if (IC_TRUE (ic))
4538     {
4539       symbol *nlbl = newiTempLabel (NULL);
4540       emit2 ("jp !tlabel", nlbl->key + 100);
4541       emitLabel (tlbl->key + 100);
4542       emit2 ("jp !tlabel", IC_TRUE (ic)->key + 100);
4543       emitLabel (nlbl->key + 100);
4544     }
4545   else
4546     {
4547       emit2 ("jp !tlabel", IC_FALSE (ic)->key + 100);
4548       emitLabel (tlbl->key + 100);
4549     }
4550   ic->generated = 1;
4551 }
4552
4553 /*-----------------------------------------------------------------*/
4554 /* genAnd  - code for and                                          */
4555 /*-----------------------------------------------------------------*/
4556 static void
4557 genAnd (iCode * ic, iCode * ifx)
4558 {
4559   operand *left, *right, *result;
4560   int size, offset = 0;
4561   unsigned long lit = 0L;
4562   int bytelit = 0;
4563
4564   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4565   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4566   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4567
4568   /* if left is a literal & right is not then exchange them */
4569   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4570       AOP_NEEDSACC (left))
4571     {
4572       operand *tmp = right;
4573       right = left;
4574       left = tmp;
4575     }
4576
4577   /* if result = right then exchange them */
4578   if (sameRegs (AOP (result), AOP (right)))
4579     {
4580       operand *tmp = right;
4581       right = left;
4582       left = tmp;
4583     }
4584
4585   /* if right is bit then exchange them */
4586   if (AOP_TYPE (right) == AOP_CRY &&
4587       AOP_TYPE (left) != AOP_CRY)
4588     {
4589       operand *tmp = right;
4590       right = left;
4591       left = tmp;
4592     }
4593   if (AOP_TYPE (right) == AOP_LIT)
4594     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4595
4596   size = AOP_SIZE (result);
4597
4598   if (AOP_TYPE (left) == AOP_CRY)
4599     {
4600       wassertl (0, "Tried to perform an AND with a bit as an operand");
4601       goto release;
4602     }
4603
4604   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4605   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4606   if ((AOP_TYPE (right) == AOP_LIT) &&
4607       (AOP_TYPE (result) == AOP_CRY) &&
4608       (AOP_TYPE (left) != AOP_CRY))
4609     {
4610       symbol *tlbl = newiTempLabel (NULL);
4611       int sizel = AOP_SIZE (left);
4612       if (size)
4613         {
4614           /* PENDING: Test case for this. */
4615           emit2 ("scf");
4616         }
4617       while (sizel--)
4618         {
4619           if ((bytelit = ((lit >> (offset * 8)) & 0x0FFL)) != 0x0L)
4620             {
4621               _moveA (aopGet (AOP (left), offset, FALSE));
4622               if (bytelit != 0x0FFL)
4623                 {
4624                   emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4625                 }
4626               else
4627                 {
4628                   /* For the flags */
4629                   emit2 ("or a,a");
4630                 }
4631               emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4632             }
4633               offset++;
4634         }
4635       // bit = left & literal
4636       if (size)
4637         {
4638           emit2 ("clr c");
4639           emit2 ("!tlabeldef", tlbl->key + 100);
4640         }
4641       // if(left & literal)
4642       else
4643         {
4644           if (ifx)
4645             {
4646               jmpTrueOrFalse (ifx, tlbl);
4647             }
4648           goto release;
4649         }
4650       outBitC (result);
4651       goto release;
4652     }
4653
4654   /* if left is same as result */
4655   if (sameRegs (AOP (result), AOP (left)))
4656     {
4657       for (; size--; offset++)
4658         {
4659           if (AOP_TYPE (right) == AOP_LIT)
4660             {
4661               if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4662                 continue;
4663               else
4664                 {
4665                   if (bytelit == 0)
4666                     aopPut (AOP (result), "!zero", offset);
4667                   else
4668                     {
4669                       _moveA (aopGet (AOP (left), offset, FALSE));
4670                       emit2 ("and a,%s",
4671                                 aopGet (AOP (right), offset, FALSE));
4672                       aopPut (AOP (left), "a", offset);
4673                     }
4674                 }
4675
4676             }
4677           else
4678             {
4679               if (AOP_TYPE (left) == AOP_ACC)
4680                 {
4681                   wassertl (0, "Tried to perform an AND where the left operand is allocated into A");
4682                 }
4683               else
4684                 {
4685                   _moveA (aopGet (AOP (left), offset, FALSE));
4686                   emit2 ("and a,%s",
4687                             aopGet (AOP (right), offset, FALSE));
4688                   aopPut (AOP (left), "a", offset);
4689                 }
4690             }
4691         }
4692     }
4693   else
4694     {
4695       // left & result in different registers
4696       if (AOP_TYPE (result) == AOP_CRY)
4697         {
4698           wassertl (0, "Tried to AND where the result is in carry");
4699         }
4700       else
4701         {
4702           for (; (size--); offset++)
4703             {
4704               // normal case
4705               // result = left & right
4706               if (AOP_TYPE (right) == AOP_LIT)
4707                 {
4708                   if ((bytelit = (int) ((lit >> (offset * 8)) & 0x0FFL)) == 0x0FF)
4709                     {
4710                       aopPut (AOP (result),
4711                               aopGet (AOP (left), offset, FALSE),
4712                               offset);
4713                       continue;
4714                     }
4715                   else if (bytelit == 0)
4716                     {
4717                       aopPut (AOP (result), "!zero", offset);
4718                       continue;
4719                     }
4720                 }
4721               // faster than result <- left, anl result,right
4722               // and better if result is SFR
4723               if (AOP_TYPE (left) == AOP_ACC)
4724                 emit2 ("and a,%s", aopGet (AOP (right), offset, FALSE));
4725               else
4726                 {
4727                   _moveA (aopGet (AOP (left), offset, FALSE));
4728                   emit2 ("and a,%s",
4729                             aopGet (AOP (right), offset, FALSE));
4730                 }
4731               aopPut (AOP (result), "a", offset);
4732             }
4733         }
4734
4735     }
4736
4737 release:
4738   freeAsmop (left, NULL, ic);
4739   freeAsmop (right, NULL, ic);
4740   freeAsmop (result, NULL, ic);
4741 }
4742
4743 /*-----------------------------------------------------------------*/
4744 /* genOr  - code for or                                            */
4745 /*-----------------------------------------------------------------*/
4746 static void
4747 genOr (iCode * ic, iCode * ifx)
4748 {
4749   operand *left, *right, *result;
4750   int size, offset = 0;
4751   unsigned long lit = 0L;
4752   int bytelit = 0;
4753
4754   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4755   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4756   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4757
4758   /* if left is a literal & right is not then exchange them */
4759   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4760       AOP_NEEDSACC (left))
4761     {
4762       operand *tmp = right;
4763       right = left;
4764       left = tmp;
4765     }
4766
4767   /* if result = right then exchange them */
4768   if (sameRegs (AOP (result), AOP (right)))
4769     {
4770       operand *tmp = right;
4771       right = left;
4772       left = tmp;
4773     }
4774
4775   /* if right is bit then exchange them */
4776   if (AOP_TYPE (right) == AOP_CRY &&
4777       AOP_TYPE (left) != AOP_CRY)
4778     {
4779       operand *tmp = right;
4780       right = left;
4781       left = tmp;
4782     }
4783   if (AOP_TYPE (right) == AOP_LIT)
4784     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4785
4786   size = AOP_SIZE (result);
4787
4788   if (AOP_TYPE (left) == AOP_CRY)
4789     {
4790       wassertl (0, "Tried to OR where left is a bit");
4791       goto release;
4792     }
4793
4794   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
4795   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
4796   if ((AOP_TYPE (right) == AOP_LIT) &&
4797       (AOP_TYPE (result) == AOP_CRY) &&
4798       (AOP_TYPE (left) != AOP_CRY))
4799     {
4800       symbol *tlbl = newiTempLabel (NULL);
4801       int sizel = AOP_SIZE (left);
4802
4803       if (size)
4804         {
4805           wassertl (0, "Result is assigned to a bit");
4806         }
4807       /* PENDING: Modeled after the AND code which is inefficent. */
4808       while (sizel--)
4809         {
4810           bytelit = (lit >> (offset * 8)) & 0x0FFL;
4811
4812           _moveA (aopGet (AOP (left), offset, FALSE));
4813           /* OR with any literal is the same as OR with itself. */
4814           emit2 ("or a,a");
4815           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4816
4817           offset++;
4818         }
4819       if (ifx)
4820         {
4821           jmpTrueOrFalse (ifx, tlbl);
4822         }
4823       goto release;
4824     }
4825
4826   /* if left is same as result */
4827   if (sameRegs (AOP (result), AOP (left)))
4828     {
4829       for (; size--; offset++)
4830         {
4831           if (AOP_TYPE (right) == AOP_LIT)
4832             {
4833               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4834                 continue;
4835               else
4836                 {
4837                   _moveA (aopGet (AOP (left), offset, FALSE));
4838                   emit2 ("or a,%s",
4839                             aopGet (AOP (right), offset, FALSE));
4840                   aopPut (AOP (result), "a", offset);
4841                 }
4842             }
4843           else
4844             {
4845               if (AOP_TYPE (left) == AOP_ACC)
4846                 emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4847               else
4848                 {
4849                   _moveA (aopGet (AOP (left), offset, FALSE));
4850                   emit2 ("or a,%s",
4851                             aopGet (AOP (right), offset, FALSE));
4852                   aopPut (AOP (result), "a", offset);
4853                 }
4854             }
4855         }
4856     }
4857   else
4858     {
4859       // left & result in different registers
4860       if (AOP_TYPE (result) == AOP_CRY)
4861         {
4862           wassertl (0, "Result of OR is in a bit");
4863         }
4864       else
4865         for (; (size--); offset++)
4866           {
4867             // normal case
4868             // result = left & right
4869             if (AOP_TYPE (right) == AOP_LIT)
4870               {
4871                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4872                   {
4873                     aopPut (AOP (result),
4874                             aopGet (AOP (left), offset, FALSE),
4875                             offset);
4876                     continue;
4877                   }
4878               }
4879             // faster than result <- left, anl result,right
4880             // and better if result is SFR
4881             if (AOP_TYPE (left) == AOP_ACC)
4882               emit2 ("or a,%s", aopGet (AOP (right), offset, FALSE));
4883             else
4884               {
4885                 _moveA (aopGet (AOP (left), offset, FALSE));
4886                 emit2 ("or a,%s",
4887                           aopGet (AOP (right), offset, FALSE));
4888               }
4889             aopPut (AOP (result), "a", offset);
4890             /* PENDING: something weird is going on here.  Add exception. */
4891             if (AOP_TYPE (result) == AOP_ACC)
4892               break;
4893           }
4894     }
4895
4896 release:
4897   freeAsmop (left, NULL, ic);
4898   freeAsmop (right, NULL, ic);
4899   freeAsmop (result, NULL, ic);
4900 }
4901
4902 /*-----------------------------------------------------------------*/
4903 /* genXor - code for xclusive or                                   */
4904 /*-----------------------------------------------------------------*/
4905 static void
4906 genXor (iCode * ic, iCode * ifx)
4907 {
4908   operand *left, *right, *result;
4909   int size, offset = 0;
4910   unsigned long lit = 0L;
4911
4912   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
4913   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
4914   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
4915
4916   /* if left is a literal & right is not then exchange them */
4917   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) ||
4918       AOP_NEEDSACC (left))
4919     {
4920       operand *tmp = right;
4921       right = left;
4922       left = tmp;
4923     }
4924
4925   /* if result = right then exchange them */
4926   if (sameRegs (AOP (result), AOP (right)))
4927     {
4928       operand *tmp = right;
4929       right = left;
4930       left = tmp;
4931     }
4932
4933   /* if right is bit then exchange them */
4934   if (AOP_TYPE (right) == AOP_CRY &&
4935       AOP_TYPE (left) != AOP_CRY)
4936     {
4937       operand *tmp = right;
4938       right = left;
4939       left = tmp;
4940     }
4941   if (AOP_TYPE (right) == AOP_LIT)
4942     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
4943
4944   size = AOP_SIZE (result);
4945
4946   if (AOP_TYPE (left) == AOP_CRY)
4947     {
4948       wassertl (0, "Tried to XOR a bit");
4949       goto release;
4950     }
4951
4952   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
4953   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
4954   if ((AOP_TYPE (right) == AOP_LIT) &&
4955       (AOP_TYPE (result) == AOP_CRY) &&
4956       (AOP_TYPE (left) != AOP_CRY))
4957     {
4958       symbol *tlbl = newiTempLabel (NULL);
4959       int sizel = AOP_SIZE (left);
4960
4961       if (size)
4962         {
4963           /* PENDING: Test case for this. */
4964           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
4965         }
4966       while (sizel--)
4967         {
4968           _moveA (aopGet (AOP (left), offset, FALSE));
4969           emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
4970           emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
4971           offset++;
4972         }
4973       if (ifx)
4974         {
4975           jmpTrueOrFalse (ifx, tlbl);
4976         }
4977       else
4978         {
4979           wassertl (0, "Result of XOR was destined for a bit");
4980         }
4981       goto release;
4982     }
4983
4984   /* if left is same as result */
4985   if (sameRegs (AOP (result), AOP (left)))
4986     {
4987       for (; size--; offset++)
4988         {
4989           if (AOP_TYPE (right) == AOP_LIT)
4990             {
4991               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
4992                 continue;
4993               else
4994                 {
4995                   _moveA (aopGet (AOP (right), offset, FALSE));
4996                   emit2 ("xor a,%s",
4997                             aopGet (AOP (left), offset, FALSE));
4998                   aopPut (AOP (result), "a", offset);
4999                 }
5000             }
5001           else
5002             {
5003               if (AOP_TYPE (left) == AOP_ACC)
5004                 {
5005                   emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5006                 }
5007               else
5008                 {
5009                   _moveA (aopGet (AOP (right), offset, FALSE));
5010                   emit2 ("xor a,%s",
5011                             aopGet (AOP (left), offset, FALSE));
5012                   aopPut (AOP (result), "a", 0);
5013                 }
5014             }
5015         }
5016     }
5017   else
5018     {
5019       // left & result in different registers
5020       if (AOP_TYPE (result) == AOP_CRY)
5021         {
5022           wassertl (0, "Result of XOR is in a bit");
5023         }
5024       else
5025         for (; (size--); offset++)
5026           {
5027             // normal case
5028             // result = left & right
5029             if (AOP_TYPE (right) == AOP_LIT)
5030               {
5031                 if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
5032                   {
5033                     aopPut (AOP (result),
5034                             aopGet (AOP (left), offset, FALSE),
5035                             offset);
5036                     continue;
5037                   }
5038               }
5039             // faster than result <- left, anl result,right
5040             // and better if result is SFR
5041             if (AOP_TYPE (left) == AOP_ACC) 
5042               {
5043                 emit2 ("xor a,%s", aopGet (AOP (right), offset, FALSE));
5044               }
5045             else
5046               {
5047                 _moveA (aopGet (AOP (right), offset, FALSE));
5048                 emit2 ("xor a,%s",
5049                           aopGet (AOP (left), offset, FALSE));
5050               }
5051             aopPut (AOP (result), "a", offset);
5052           }
5053     }
5054
5055 release:
5056   freeAsmop (left, NULL, ic);
5057   freeAsmop (right, NULL, ic);
5058   freeAsmop (result, NULL, ic);
5059 }
5060
5061 /*-----------------------------------------------------------------*/
5062 /* genInline - write the inline code out                           */
5063 /*-----------------------------------------------------------------*/
5064 static void
5065 genInline (iCode * ic)
5066 {
5067   char *buffer, *bp, *bp1;
5068
5069   _G.lines.isInline += (!options.asmpeep);
5070
5071   buffer = bp = bp1 = Safe_calloc(1, strlen(IC_INLINE(ic))+1);
5072   strcpy (buffer, IC_INLINE (ic));
5073
5074   /* emit each line as a code */
5075   while (*bp)
5076     {
5077       if (*bp == '\n')
5078         {
5079           *bp++ = '\0';
5080           emit2 (bp1);
5081           bp1 = bp;
5082         }
5083       else
5084         {
5085           if (*bp == ':')
5086             {
5087               bp++;
5088               *bp = '\0';
5089               bp++;
5090               emit2 (bp1);
5091               bp1 = bp;
5092             }
5093           else
5094             bp++;
5095         }
5096     }
5097   if (bp1 != bp)
5098     emit2 (bp1);
5099   _G.lines.isInline -= (!options.asmpeep);
5100
5101 }
5102
5103 /*-----------------------------------------------------------------*/
5104 /* genRRC - rotate right with carry                                */
5105 /*-----------------------------------------------------------------*/
5106 static void
5107 genRRC (iCode * ic)
5108 {
5109   wassert (0);
5110 }
5111
5112 /*-----------------------------------------------------------------*/
5113 /* genRLC - generate code for rotate left with carry               */
5114 /*-----------------------------------------------------------------*/
5115 static void
5116 genRLC (iCode * ic)
5117 {
5118   wassert (0);
5119 }
5120
5121 /*-----------------------------------------------------------------*/
5122 /* genGetHbit - generates code get highest order bit               */
5123 /*-----------------------------------------------------------------*/
5124 static void
5125 genGetHbit (iCode * ic)
5126 {
5127   operand *left, *result;
5128   left = IC_LEFT (ic);
5129   result = IC_RESULT (ic);
5130   aopOp (left, ic, FALSE, FALSE);
5131   aopOp (result, ic, FALSE, FALSE);
5132
5133   /* get the highest order byte into a */
5134   emit2("ld a,%s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
5135
5136   if (AOP_TYPE (result) == AOP_CRY)
5137     {
5138       emit2 ("rl a");
5139       outBitC (result);
5140     }
5141   else
5142     {
5143       emit2 ("rlc a");
5144       /* PENDING: For re-target. */
5145       emit2 ("and a,#1");
5146       outAcc (result);
5147     }
5148
5149
5150   freeAsmop (left, NULL, ic);
5151   freeAsmop (result, NULL, ic);
5152 }
5153
5154 static void
5155 emitRsh2 (asmop *aop, int size, int is_signed)
5156 {
5157   int offset = 0;
5158
5159   while (size--)
5160     {
5161       const char *l = aopGet (aop, size, FALSE);
5162       if (offset == 0)
5163         {
5164           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5165         }
5166       else
5167         {
5168           emit2 ("rr %s", l);
5169         }
5170       offset++;
5171     }
5172 }
5173
5174 /*-----------------------------------------------------------------*/
5175 /* shiftR2Left2Result - shift right two bytes from left to result  */
5176 /*-----------------------------------------------------------------*/
5177 static void
5178 shiftR2Left2Result (operand * left, int offl,
5179                     operand * result, int offr,
5180                     int shCount, int is_signed)
5181 {
5182   int size = 2;
5183   symbol *tlbl, *tlbl1;
5184
5185   movLeft2Result (left, offl, result, offr, 0);
5186   movLeft2Result (left, offl + 1, result, offr + 1, 0);
5187
5188   /*  if (AOP(result)->type == AOP_REG) { */
5189   
5190   tlbl = newiTempLabel (NULL);
5191   tlbl1 = newiTempLabel (NULL);
5192
5193   /* Left is already in result - so now do the shift */
5194   if (shCount <= 4)
5195     {
5196       while (shCount--)
5197         {
5198           emitRsh2 (AOP (result), size, is_signed);
5199         }
5200     }
5201   else
5202     {
5203       emit2 ("ld a,!immedbyte+1", shCount);
5204       emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5205       emitLabel (tlbl->key + 100);
5206
5207       emitRsh2 (AOP (result), size, is_signed);
5208
5209       emitLabel (tlbl1->key + 100);
5210       emit2 ("dec a");
5211       emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5212     }
5213 }
5214
5215 /*-----------------------------------------------------------------*/
5216 /* shiftL2Left2Result - shift left two bytes from left to result   */
5217 /*-----------------------------------------------------------------*/
5218 static void
5219 shiftL2Left2Result (operand * left, int offl,
5220                     operand * result, int offr, int shCount)
5221 {
5222   if (sameRegs (AOP (result), AOP (left)) &&
5223       ((offl + MSB16) == offr))
5224     {
5225       wassert (0);
5226     }
5227   else
5228     {
5229       /* Copy left into result */
5230       movLeft2Result (left, offl, result, offr, 0);
5231       movLeft2Result (left, offl + 1, result, offr + 1, 0);
5232     }
5233   /* PENDING: for now just see if it'll work. */
5234   /*if (AOP(result)->type == AOP_REG) { */
5235   {
5236     int size = 2;
5237     int offset = 0;
5238     symbol *tlbl, *tlbl1;
5239     const char *l;
5240
5241     tlbl = newiTempLabel (NULL);
5242     tlbl1 = newiTempLabel (NULL);
5243
5244     /* Left is already in result - so now do the shift */
5245     if (shCount > 1)
5246       {
5247         emit2 ("ld a,!immedbyte+1", shCount);
5248         emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5249         emitLabel (tlbl->key + 100);
5250       }
5251
5252     while (size--)
5253       {
5254         l = aopGet (AOP (result), offset, FALSE);
5255
5256         if (offset == 0)
5257           {
5258             emit2 ("sla %s", l);
5259           }
5260         else
5261           {
5262             emit2 ("rl %s", l);
5263           }
5264
5265         offset++;
5266       }
5267     if (shCount > 1)
5268       {
5269         emitLabel (tlbl1->key + 100);
5270         emit2 ("dec a");
5271         emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5272       }
5273   }
5274 }
5275
5276 /*-----------------------------------------------------------------*/
5277 /* AccRol - rotate left accumulator by known count                 */
5278 /*-----------------------------------------------------------------*/
5279 static void
5280 AccRol (int shCount)
5281 {
5282   shCount &= 0x0007;            // shCount : 0..7
5283
5284   switch (shCount)
5285     {
5286     case 0:
5287       break;
5288     case 1:
5289       emit2 ("sla a");
5290       break;
5291     case 2:
5292       emit2 ("sla a");
5293       emit2 ("rl a");
5294       break;
5295     case 3:
5296       emit2 ("sla a");
5297       emit2 ("rl a");
5298       emit2 ("rl a");
5299       break;
5300     case 4:
5301       emit2 ("sla a");
5302       emit2 ("rl a");
5303       emit2 ("rl a");
5304       emit2 ("rl a");
5305       break;
5306     case 5:
5307       emit2 ("srl a");
5308       emit2 ("rr a");
5309       emit2 ("rr a");
5310       break;
5311     case 6:
5312       emit2 ("srl a");
5313       emit2 ("rr a");
5314       break;
5315     case 7:
5316       emit2 ("srl a");
5317       break;
5318     }
5319 }
5320
5321 /*-----------------------------------------------------------------*/
5322 /* AccLsh - left shift accumulator by known count                  */
5323 /*-----------------------------------------------------------------*/
5324 static void
5325 AccLsh (int shCount)
5326 {
5327   static const unsigned char SLMask[] =
5328     {
5329       0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
5330     };
5331
5332   if (shCount != 0)
5333     {
5334       if (shCount == 1)
5335         {
5336           emit2 ("add a,a");
5337         }
5338       else if (shCount == 2)
5339         {
5340           emit2 ("add a,a");
5341           emit2 ("add a,a");
5342         }
5343       else
5344         {
5345           /* rotate left accumulator */
5346           AccRol (shCount);
5347           /* and kill the lower order bits */
5348           emit2 ("and a,!immedbyte", SLMask[shCount]);
5349         }
5350     }
5351 }
5352
5353 /*-----------------------------------------------------------------*/
5354 /* shiftL1Left2Result - shift left one byte from left to result    */
5355 /*-----------------------------------------------------------------*/
5356 static void
5357 shiftL1Left2Result (operand * left, int offl,
5358                     operand * result, int offr, int shCount)
5359 {
5360   const char *l;
5361   l = aopGet (AOP (left), offl, FALSE);
5362   _moveA (l);
5363   /* shift left accumulator */
5364   AccLsh (shCount);
5365   aopPut (AOP (result), "a", offr);
5366 }
5367
5368
5369 /*-----------------------------------------------------------------*/
5370 /* genlshTwo - left shift two bytes by known amount != 0           */
5371 /*-----------------------------------------------------------------*/
5372 static void
5373 genlshTwo (operand * result, operand * left, int shCount)
5374 {
5375   int size = AOP_SIZE (result);
5376
5377   wassert (size == 2);
5378
5379   /* if shCount >= 8 */
5380   if (shCount >= 8)
5381     {
5382       shCount -= 8;
5383       if (size > 1)
5384         {
5385           if (shCount)
5386             {
5387               movLeft2Result (left, LSB, result, MSB16, 0);
5388               aopPut (AOP (result), "!zero", 0);
5389               shiftL1Left2Result (left, LSB, result, MSB16, shCount);
5390             }
5391           else
5392             {
5393               movLeft2Result (left, LSB, result, MSB16, 0);
5394               aopPut (AOP (result), "!zero", 0);
5395             }
5396         }
5397       else
5398         {
5399           aopPut (AOP (result), "!zero", LSB);
5400         }
5401     }
5402   /*  1 <= shCount <= 7 */
5403   else
5404     {
5405       if (size == 1)
5406         {
5407           wassert (0);
5408         }
5409       else
5410         {
5411           shiftL2Left2Result (left, LSB, result, LSB, shCount);
5412         }
5413     }
5414 }
5415
5416 /*-----------------------------------------------------------------*/
5417 /* genlshOne - left shift a one byte quantity by known count       */
5418 /*-----------------------------------------------------------------*/
5419 static void
5420 genlshOne (operand * result, operand * left, int shCount)
5421 {
5422   shiftL1Left2Result (left, LSB, result, LSB, shCount);
5423 }
5424
5425 /*-----------------------------------------------------------------*/
5426 /* genLeftShiftLiteral - left shifting by known count              */
5427 /*-----------------------------------------------------------------*/
5428 static void
5429 genLeftShiftLiteral (operand * left,
5430                      operand * right,
5431                      operand * result,
5432                      iCode * ic)
5433 {
5434   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5435   int size;
5436
5437   freeAsmop (right, NULL, ic);
5438
5439   aopOp (left, ic, FALSE, FALSE);
5440   aopOp (result, ic, FALSE, FALSE);
5441
5442   size = getSize (operandType (result));
5443
5444   /* I suppose that the left size >= result size */
5445   if (shCount == 0)
5446     {
5447       wassert (0);
5448     }
5449
5450   else if (shCount >= (size * 8)) 
5451     {
5452       while (size--)
5453         {
5454           aopPut (AOP (result), "!zero", size);
5455         }
5456     }
5457   else
5458     {
5459       switch (size)
5460         {
5461         case 1:
5462           genlshOne (result, left, shCount);
5463           break;
5464         case 2:
5465           genlshTwo (result, left, shCount);
5466           break;
5467         case 4:
5468           wassertl (0, "Shifting of longs is currently unsupported");
5469           break;
5470         default:
5471           wassert (0);
5472         }
5473     }
5474   freeAsmop (left, NULL, ic);
5475   freeAsmop (result, NULL, ic);
5476 }
5477
5478 /*-----------------------------------------------------------------*/
5479 /* genLeftShift - generates code for left shifting                 */
5480 /*-----------------------------------------------------------------*/
5481 static void
5482 genLeftShift (iCode * ic)
5483 {
5484   int size, offset;
5485   const char *l;
5486   symbol *tlbl, *tlbl1;
5487   operand *left, *right, *result;
5488
5489   right = IC_RIGHT (ic);
5490   left = IC_LEFT (ic);
5491   result = IC_RESULT (ic);
5492
5493   aopOp (right, ic, FALSE, FALSE);
5494
5495   /* if the shift count is known then do it
5496      as efficiently as possible */
5497   if (AOP_TYPE (right) == AOP_LIT)
5498     {
5499       genLeftShiftLiteral (left, right, result, ic);
5500       return;
5501     }
5502
5503   /* shift count is unknown then we have to form a loop get the loop
5504      count in B : Note: we take only the lower order byte since
5505      shifting more that 32 bits make no sense anyway, ( the largest
5506      size of an object can be only 32 bits ) */
5507   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5508   emit2 ("inc a");
5509   freeAsmop (right, NULL, ic);
5510   aopOp (left, ic, FALSE, FALSE);
5511   aopOp (result, ic, FALSE, FALSE);
5512
5513   /* now move the left to the result if they are not the
5514      same */
5515
5516   if (!sameRegs (AOP (left), AOP (result)))
5517     {
5518
5519       size = AOP_SIZE (result);
5520       offset = 0;
5521       while (size--)
5522         {
5523           l = aopGet (AOP (left), offset, FALSE);
5524           aopPut (AOP (result), l, offset);
5525           offset++;
5526         }
5527     }
5528
5529   tlbl = newiTempLabel (NULL);
5530   size = AOP_SIZE (result);
5531   offset = 0;
5532   tlbl1 = newiTempLabel (NULL);
5533
5534   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5535   emitLabel (tlbl->key + 100);
5536   l = aopGet (AOP (result), offset, FALSE);
5537
5538   while (size--)
5539     {
5540       l = aopGet (AOP (result), offset, FALSE);
5541
5542       if (offset == 0)
5543         {
5544           emit2 ("sla %s", l);
5545         }
5546       else
5547         {
5548           emit2 ("rl %s", l);
5549         }
5550       offset++;
5551     }
5552   emitLabel (tlbl1->key + 100);
5553   emit2 ("dec a");
5554   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5555
5556   freeAsmop (left, NULL, ic);
5557   freeAsmop (result, NULL, ic);
5558 }
5559
5560 /*-----------------------------------------------------------------*/
5561 /* genrshOne - left shift two bytes by known amount != 0           */
5562 /*-----------------------------------------------------------------*/
5563 static void
5564 genrshOne (operand * result, operand * left, int shCount, int is_signed)
5565 {
5566   /* Errk */
5567   int size = AOP_SIZE (result);
5568   const char *l;
5569
5570   wassert (size == 1);
5571   wassert (shCount < 8);
5572
5573   l = aopGet (AOP (left), 0, FALSE);
5574
5575   if (AOP (result)->type == AOP_REG)
5576     {
5577       aopPut (AOP (result), l, 0);
5578       l = aopGet (AOP (result), 0, FALSE);
5579       while (shCount--)
5580         {
5581           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5582         }
5583     }
5584   else
5585     {
5586       _moveA (l);
5587       while (shCount--)
5588         {
5589           emit2 ("%s a", is_signed ? "sra" : "srl");
5590         }
5591       aopPut (AOP (result), "a", 0);
5592     }
5593 }
5594
5595 /*-----------------------------------------------------------------*/
5596 /* AccRsh - right shift accumulator by known count                 */
5597 /*-----------------------------------------------------------------*/
5598 static void
5599 AccRsh (int shCount)
5600 {
5601   static const unsigned char SRMask[] =
5602     {
5603       0xFF, 0x7F, 0x3F, 0x1F, 0x0F, 0x07, 0x03, 0x01, 0x00
5604     };
5605
5606   if (shCount != 0)
5607     {
5608       /* rotate right accumulator */
5609       AccRol (8 - shCount);
5610       /* and kill the higher order bits */
5611       emit2 ("and a,!immedbyte", SRMask[shCount]);
5612     }
5613 }
5614
5615 /*-----------------------------------------------------------------*/
5616 /* shiftR1Left2Result - shift right one byte from left to result   */
5617 /*-----------------------------------------------------------------*/
5618 static void
5619 shiftR1Left2Result (operand * left, int offl,
5620                     operand * result, int offr,
5621                     int shCount, int sign)
5622 {
5623   _moveA (aopGet (AOP (left), offl, FALSE));
5624   if (sign)
5625     {
5626       while (shCount--)
5627         {
5628           emit2 ("%s a", sign ? "sra" : "srl");
5629         }
5630     }
5631   else
5632     {
5633       AccRsh (shCount);
5634     }
5635   aopPut (AOP (result), "a", offr);
5636 }
5637
5638 /*-----------------------------------------------------------------*/
5639 /* genrshTwo - right shift two bytes by known amount != 0          */
5640 /*-----------------------------------------------------------------*/
5641 static void
5642 genrshTwo (operand * result, operand * left,
5643            int shCount, int sign)
5644 {
5645   /* if shCount >= 8 */
5646   if (shCount >= 8)
5647     {
5648       shCount -= 8;
5649       if (shCount)
5650         {
5651           shiftR1Left2Result (left, MSB16, result, LSB,
5652                               shCount, sign);
5653         }
5654       else
5655         {
5656           movLeft2Result (left, MSB16, result, LSB, sign);
5657         }
5658       if (sign)
5659         {
5660           /* Sign extend the result */
5661           _moveA(aopGet (AOP (result), 0, FALSE));
5662           emit2 ("rlc a");
5663           emit2 ("sbc a,a");
5664
5665           aopPut (AOP (result), ACC_NAME, MSB16);
5666         }
5667       else
5668         {
5669           aopPut (AOP (result), "!zero", 1);
5670         }
5671     }
5672   /*  1 <= shCount <= 7 */
5673   else
5674     {
5675       shiftR2Left2Result (left, LSB, result, LSB, shCount, sign);
5676     }
5677 }
5678
5679 /*-----------------------------------------------------------------*/
5680 /* genRightShiftLiteral - left shifting by known count              */
5681 /*-----------------------------------------------------------------*/
5682 static void
5683 genRightShiftLiteral (operand * left,
5684                       operand * right,
5685                       operand * result,
5686                       iCode * ic,
5687                       int sign)
5688 {
5689   int shCount = (int) floatFromVal (AOP (right)->aopu.aop_lit);
5690   int size;
5691
5692   freeAsmop (right, NULL, ic);
5693
5694   aopOp (left, ic, FALSE, FALSE);
5695   aopOp (result, ic, FALSE, FALSE);
5696
5697   size = getSize (operandType (result));
5698
5699   /* I suppose that the left size >= result size */
5700   if (shCount == 0)
5701     {
5702       wassert (0);
5703     }
5704
5705   else if (shCount >= (size * 8))
5706     while (size--)
5707       aopPut (AOP (result), "!zero", size);
5708   else
5709     {
5710       switch (size)
5711         {
5712         case 1:
5713           genrshOne (result, left, shCount, sign);
5714           break;
5715         case 2:
5716           genrshTwo (result, left, shCount, sign);
5717           break;
5718         case 4:
5719           wassertl (0, "Asked to shift right a long which should be a function call");
5720           break;
5721         default:
5722           wassertl (0, "Entered default case in right shift delegate");
5723         }
5724     }
5725   freeAsmop (left, NULL, ic);
5726   freeAsmop (result, NULL, ic);
5727 }
5728
5729 /*-----------------------------------------------------------------*/
5730 /* genRightShift - generate code for right shifting                */
5731 /*-----------------------------------------------------------------*/
5732 static void
5733 genRightShift (iCode * ic)
5734 {
5735   operand *right, *left, *result;
5736   sym_link *retype;
5737   int size, offset, first = 1;
5738   const char *l;
5739   bool is_signed;
5740
5741   symbol *tlbl, *tlbl1;
5742
5743   /* if signed then we do it the hard way preserve the
5744      sign bit moving it inwards */
5745   retype = getSpec (operandType (IC_RESULT (ic)));
5746
5747   is_signed = !SPEC_USIGN (retype);
5748
5749   /* signed & unsigned types are treated the same : i.e. the
5750      signed is NOT propagated inwards : quoting from the
5751      ANSI - standard : "for E1 >> E2, is equivalent to division
5752      by 2**E2 if unsigned or if it has a non-negative value,
5753      otherwise the result is implementation defined ", MY definition
5754      is that the sign does not get propagated */
5755
5756   right = IC_RIGHT (ic);
5757   left = IC_LEFT (ic);
5758   result = IC_RESULT (ic);
5759
5760   aopOp (right, ic, FALSE, FALSE);
5761
5762   /* if the shift count is known then do it
5763      as efficiently as possible */
5764   if (AOP_TYPE (right) == AOP_LIT)
5765     {
5766       genRightShiftLiteral (left, right, result, ic, is_signed);
5767       return;
5768     }
5769
5770   aopOp (left, ic, FALSE, FALSE);
5771   aopOp (result, ic, FALSE, FALSE);
5772
5773   /* now move the left to the result if they are not the
5774      same */
5775   if (!sameRegs (AOP (left), AOP (result)) &&
5776       AOP_SIZE (result) > 1)
5777     {
5778
5779       size = AOP_SIZE (result);
5780       offset = 0;
5781       while (size--)
5782         {
5783           l = aopGet (AOP (left), offset, FALSE);
5784           aopPut (AOP (result), l, offset);
5785           offset++;
5786         }
5787     }
5788
5789   emit2 ("ld a,%s", aopGet (AOP (right), 0, FALSE));
5790   emit2 ("inc a");
5791   freeAsmop (right, NULL, ic);
5792
5793   tlbl = newiTempLabel (NULL);
5794   tlbl1 = newiTempLabel (NULL);
5795   size = AOP_SIZE (result);
5796   offset = size - 1;
5797
5798   emit2 ("!shortjp !tlabel", tlbl1->key + 100);
5799   emitLabel (tlbl->key + 100);
5800   while (size--)
5801     {
5802       l = aopGet (AOP (result), offset--, FALSE);
5803       if (first)
5804         {
5805           emit2 ("%s %s", is_signed ? "sra" : "srl", l);
5806           first = 0;
5807         }
5808       else
5809         {
5810           emit2 ("rr %s", l);
5811         }
5812     }
5813   emitLabel (tlbl1->key + 100);
5814   emit2 ("dec a");
5815   emit2 ("!shortjp nz,!tlabel", tlbl->key + 100);
5816
5817   freeAsmop (left, NULL, ic);
5818   freeAsmop (result, NULL, ic);
5819 }
5820
5821 /*-----------------------------------------------------------------*/
5822 /* genGenPointerGet -  get value from generic pointer space        */
5823 /*-----------------------------------------------------------------*/
5824 static void
5825 genGenPointerGet (operand * left,
5826                   operand * result, iCode * ic)
5827 {
5828   int size, offset;
5829   sym_link *retype = getSpec (operandType (result));
5830   int pair = PAIR_HL;
5831
5832   if (IS_GB)
5833     pair = PAIR_DE;
5834
5835   aopOp (left, ic, FALSE, FALSE);
5836   aopOp (result, ic, FALSE, FALSE);
5837
5838   size = AOP_SIZE (result);
5839
5840   if (isPair (AOP (left)) && size == 1)
5841     {
5842       /* Just do it */
5843       if (isPtrPair (AOP (left)))
5844         {
5845           tsprintf (buffer, "!*pair", getPairName (AOP (left)));
5846           aopPut (AOP (result), buffer, 0);
5847         }
5848       else
5849         {
5850           emit2 ("ld a,!*pair", getPairName (AOP (left)));
5851           aopPut (AOP (result), "a", 0);
5852         }
5853       freeAsmop (left, NULL, ic);
5854       goto release;
5855     }
5856
5857   if ( getPairId( AOP (left)) == PAIR_IY)
5858     {
5859       /* Just do it */
5860       offset = 0;
5861       while (size--) 
5862         {
5863           char at[20];
5864           tsprintf (at, "!*iyx", offset);
5865           aopPut (AOP (result), at, offset);
5866           offset++;
5867         }
5868       goto release;
5869     }
5870
5871   /* For now we always load into IY */
5872   /* if this is remateriazable */
5873   fetchPair (pair, AOP (left));
5874
5875   freeAsmop (left, NULL, ic);
5876
5877   /* if bit then unpack */
5878   if (IS_BITVAR (retype))
5879     {
5880       wassert (0);
5881     }
5882   else if ( getPairId( AOP (result)) == PAIR_HL)
5883     {
5884       wassertl (size == 2, "HL must be of size 2");
5885       emit2 ("ld a,!*hl");
5886       emit2 ("inc hl");
5887       emit2 ("ld h,!*hl");
5888       emit2 ("ld l,a");
5889     }
5890   else
5891     {
5892       size = AOP_SIZE (result);
5893       offset = 0;
5894
5895       while (size--)
5896         {
5897           /* PENDING: make this better */
5898           if (!IS_GB && AOP (result)->type == AOP_REG)
5899             {
5900               aopPut (AOP (result), "!*hl", offset++);
5901             }
5902           else
5903             {
5904               emit2 ("ld a,!*pair", _pairs[pair].name);
5905               aopPut (AOP (result), "a", offset++);
5906             }
5907           if (size)
5908             {
5909               emit2 ("inc %s", _pairs[pair].name);
5910               _G.pairs[pair].offset++;
5911             }
5912         }
5913     }
5914
5915 release:
5916   freeAsmop (result, NULL, ic);
5917 }
5918
5919 /*-----------------------------------------------------------------*/
5920 /* genPointerGet - generate code for pointer get                   */
5921 /*-----------------------------------------------------------------*/
5922 static void
5923 genPointerGet (iCode * ic)
5924 {
5925   operand *left, *result;
5926   sym_link *type, *etype;
5927
5928   left = IC_LEFT (ic);
5929   result = IC_RESULT (ic);
5930
5931   /* depending on the type of pointer we need to
5932      move it to the correct pointer register */
5933   type = operandType (left);
5934   etype = getSpec (type);
5935
5936   genGenPointerGet (left, result, ic);
5937 }
5938
5939 bool
5940 isRegOrLit (asmop * aop)
5941 {
5942   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD || aop->type == AOP_HLREG)
5943     return TRUE;
5944   return FALSE;
5945 }
5946
5947 /*-----------------------------------------------------------------*/
5948 /* genGenPointerSet - stores the value into a pointer location        */
5949 /*-----------------------------------------------------------------*/
5950 static void
5951 genGenPointerSet (operand * right,
5952                   operand * result, iCode * ic)
5953 {
5954   int size, offset;
5955   sym_link *retype = getSpec (operandType (right));
5956   PAIR_ID pairId = PAIR_HL;
5957   
5958   aopOp (result, ic, FALSE, FALSE);
5959   aopOp (right, ic, FALSE, FALSE);
5960
5961   if (IS_GB)
5962     pairId = PAIR_DE;
5963
5964   size = AOP_SIZE (right);
5965
5966   /* Handle the exceptions first */
5967   if (isPair (AOP (result)) && size == 1)
5968     {
5969       /* Just do it */
5970       const char *l = aopGet (AOP (right), 0, FALSE);
5971       const char *pair = getPairName (AOP (result));
5972       if (canAssignToPtr (l) && isPtr (pair))
5973         {
5974           emit2 ("ld !*pair,%s", pair, l);
5975         }
5976       else
5977         {
5978           _moveA (l);
5979           emit2 ("ld !*pair,a", pair);
5980         }
5981       goto release;
5982     }
5983   
5984   if ( getPairId( AOP (result)) == PAIR_IY)
5985     {
5986       /* Just do it */
5987       const char *l = aopGet (AOP (right), 0, FALSE);
5988
5989       offset = 0;
5990       while (size--) 
5991         {
5992           if (canAssignToPtr (l))
5993             {
5994               emit2 ("ld !*iyx,%s", offset, aopGet( AOP(right), offset, FALSE));
5995             }
5996           else
5997             {
5998               _moveA (aopGet (AOP (right), offset, FALSE));
5999               emit2 ("ld !*iyx,a", offset);
6000             }
6001           offset++;
6002         }
6003       goto release;
6004     }
6005
6006   /* if the operand is already in dptr
6007      then we do nothing else we move the value to dptr */
6008   if (AOP_TYPE (result) != AOP_STR)
6009     {
6010       fetchPair (pairId, AOP (result));
6011     }
6012   /* so hl know contains the address */
6013   freeAsmop (result, NULL, ic);
6014
6015   /* if bit then unpack */
6016   if (IS_BITVAR (retype))
6017     {
6018       wassert (0);
6019     }
6020   else
6021     {
6022       offset = 0;
6023
6024       while (size--)
6025         {
6026           const char *l = aopGet (AOP (right), offset, FALSE);
6027           if (isRegOrLit (AOP (right)) && !IS_GB)
6028             {
6029               emit2 ("ld !*pair,%s", _pairs[pairId].name, l);
6030             }
6031           else
6032             {
6033               _moveA (l);
6034               emit2 ("ld !*pair,a", _pairs[pairId].name);
6035             }
6036           if (size)
6037             {
6038               emit2 ("inc %s", _pairs[pairId].name);
6039               _G.pairs[pairId].offset++;
6040             }
6041           offset++;
6042         }
6043     }
6044 release:
6045   freeAsmop (right, NULL, ic);
6046 }
6047
6048 /*-----------------------------------------------------------------*/
6049 /* genPointerSet - stores the value into a pointer location        */
6050 /*-----------------------------------------------------------------*/
6051 static void
6052 genPointerSet (iCode * ic)
6053 {
6054   operand *right, *result;
6055   sym_link *type, *etype;
6056
6057   right = IC_RIGHT (ic);
6058   result = IC_RESULT (ic);
6059
6060   /* depending on the type of pointer we need to
6061      move it to the correct pointer register */
6062   type = operandType (result);
6063   etype = getSpec (type);
6064
6065   genGenPointerSet (right, result, ic);
6066 }
6067
6068 /*-----------------------------------------------------------------*/
6069 /* genIfx - generate code for Ifx statement                        */
6070 /*-----------------------------------------------------------------*/
6071 static void
6072 genIfx (iCode * ic, iCode * popIc)
6073 {
6074   operand *cond = IC_COND (ic);
6075   int isbit = 0;
6076
6077   aopOp (cond, ic, FALSE, TRUE);
6078
6079   /* get the value into acc */
6080   if (AOP_TYPE (cond) != AOP_CRY)
6081     _toBoolean (cond);
6082   else
6083     isbit = 1;
6084   /* the result is now in the accumulator */
6085   freeAsmop (cond, NULL, ic);
6086
6087   /* if there was something to be popped then do it */
6088   if (popIc)
6089     genIpop (popIc);
6090
6091   /* if the condition is  a bit variable */
6092   if (isbit && IS_ITEMP (cond) &&
6093       SPIL_LOC (cond))
6094     genIfxJump (ic, SPIL_LOC (cond)->rname);
6095   else if (isbit && !IS_ITEMP (cond))
6096     genIfxJump (ic, OP_SYMBOL (cond)->rname);
6097   else
6098     genIfxJump (ic, "a");
6099
6100   ic->generated = 1;
6101 }
6102
6103 /*-----------------------------------------------------------------*/
6104 /* genAddrOf - generates code for address of                       */
6105 /*-----------------------------------------------------------------*/
6106 static void
6107 genAddrOf (iCode * ic)
6108 {
6109   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6110
6111   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6112
6113   /* if the operand is on the stack then we
6114      need to get the stack offset of this
6115      variable */
6116   if (IS_GB)
6117     {
6118       if (sym->onStack)
6119         {
6120           spillCached ();
6121           if (sym->stack <= 0)
6122             {
6123               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset);
6124             }
6125           else
6126             {
6127               setupPairFromSP (PAIR_HL, sym->stack + _G.stack.pushed + _G.stack.offset + _G.stack.param_offset);
6128             }
6129           commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6130         }
6131       else
6132         {
6133           emit2 ("ld de,!hashedstr", sym->rname);
6134           commitPair (AOP (IC_RESULT (ic)), PAIR_DE);
6135         }
6136     }
6137   else
6138     {
6139       spillCached ();
6140       if (sym->onStack)
6141         {
6142           /* if it has an offset  then we need to compute it */
6143           if (sym->stack > 0)
6144             emit2 ("ld hl,#%d+%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset, _G.stack.param_offset);
6145           else
6146             emit2 ("ld hl,#%d+%d+%d", sym->stack, _G.stack.pushed, _G.stack.offset);
6147           emit2 ("add hl,sp");
6148         }
6149       else
6150         {
6151           emit2 ("ld hl,#%s", sym->rname);
6152         }
6153       commitPair (AOP (IC_RESULT (ic)), PAIR_HL);
6154     }
6155   freeAsmop (IC_RESULT (ic), NULL, ic);
6156 }
6157
6158 /*-----------------------------------------------------------------*/
6159 /* genAssign - generate code for assignment                        */
6160 /*-----------------------------------------------------------------*/
6161 static void
6162 genAssign (iCode * ic)
6163 {
6164   operand *result, *right;
6165   int size, offset;
6166   unsigned long lit = 0L;
6167
6168   result = IC_RESULT (ic);
6169   right = IC_RIGHT (ic);
6170
6171   /* Dont bother assigning if they are the same */
6172   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6173     {
6174       emitDebug ("; (operands are equal %u)", operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)));
6175       return;
6176     }
6177
6178   aopOp (right, ic, FALSE, FALSE);
6179   aopOp (result, ic, TRUE, FALSE);
6180
6181   /* if they are the same registers */
6182   if (sameRegs (AOP (right), AOP (result)))
6183     {
6184       emitDebug ("; (registers are the same)");
6185       goto release;
6186     }
6187
6188   /* if the result is a bit */
6189   if (AOP_TYPE (result) == AOP_CRY)
6190     {
6191       wassertl (0, "Tried to assign to a bit");
6192     }
6193
6194   /* general case */
6195   size = AOP_SIZE (result);
6196   offset = 0;
6197
6198   if (AOP_TYPE (right) == AOP_LIT)
6199     {
6200     lit = (unsigned long) floatFromVal (AOP (right)->aopu.aop_lit);
6201     }
6202
6203   if (isPair (AOP (result)))
6204     {
6205       fetchPair (getPairId (AOP (result)), AOP (right));
6206     }
6207   else if ((size > 1) &&
6208            (AOP_TYPE (result) != AOP_REG) &&
6209            (AOP_TYPE (right) == AOP_LIT) &&
6210            !IS_FLOAT (operandType (right)) &&
6211            (lit < 256L))
6212     {
6213       bool fXored = FALSE;
6214       offset = 0;
6215       /* Work from the top down.
6216          Done this way so that we can use the cached copy of 0
6217          in A for a fast clear */
6218       while (size--)
6219         {
6220           if ((unsigned int) ((lit >> (offset * 8)) & 0x0FFL) == 0)
6221             {
6222               if (!fXored && size > 1)
6223                 {
6224                   emit2 ("xor a,a");
6225                   fXored = TRUE;
6226                 }
6227               if (fXored)
6228                 {
6229                   aopPut (AOP (result), "a", offset);
6230                 }
6231               else
6232                 {
6233                   aopPut (AOP (result), "!zero", offset);
6234                 }
6235             }
6236           else
6237             aopPut (AOP (result),
6238                     aopGet (AOP (right), offset, FALSE),
6239                     offset);
6240           offset++;
6241         }
6242     }
6243   else if (size == 2 && AOP_TYPE (right) == AOP_IY)
6244     {
6245       emit2 ("ld hl,(%s)", AOP (right)->aopu.aop_dir);
6246       aopPut (AOP (result), "l", LSB);
6247       aopPut (AOP (result), "h", MSB16);
6248     }
6249   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6250     {
6251       /* Special case.  Load into a and d, then load out. */
6252       _moveA (aopGet (AOP (right), 0, FALSE));
6253       emit2 ("ld e,%s", aopGet (AOP (right), 1, FALSE));
6254       aopPut (AOP (result), "a", 0);
6255       aopPut (AOP (result), "e", 1);
6256     }
6257   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && IS_GB)
6258     {
6259       /* Special case - simple memcpy */
6260       aopGet (AOP (right), LSB, FALSE);
6261       emit2 ("ld d,h");
6262       emit2 ("ld e,l");
6263       aopGet (AOP (result), LSB, FALSE);
6264
6265       while (size--)
6266         {
6267           emit2 ("ld a,(de)");
6268           /* Peephole will optimise this. */
6269           emit2 ("ld (hl),a");
6270
6271           if (size != 0)
6272             {
6273               emit2 ("inc hl");
6274               emit2 ("inc de");
6275             }
6276         }
6277       spillPair (PAIR_HL);
6278     }
6279   else
6280     {
6281       while (size--)
6282         {
6283           /* PENDING: do this check better */
6284           if (IS_GB && requiresHL (AOP (right)) && requiresHL (AOP (result)))
6285             {
6286               _moveA (aopGet (AOP (right), offset, FALSE));
6287               aopPut (AOP (result), "a", offset);
6288             }
6289           else
6290             aopPut (AOP (result),
6291                     aopGet (AOP (right), offset, FALSE),
6292                     offset);
6293           offset++;
6294         }
6295     }
6296
6297 release:
6298   freeAsmop (right, NULL, ic);
6299   freeAsmop (result, NULL, ic);
6300 }
6301
6302 /*-----------------------------------------------------------------*/
6303 /* genJumpTab - genrates code for jump table                       */
6304 /*-----------------------------------------------------------------*/
6305 static void
6306 genJumpTab (iCode * ic)
6307 {
6308   symbol *jtab;
6309   const char *l;
6310
6311   aopOp (IC_JTCOND (ic), ic, FALSE, FALSE);
6312   /* get the condition into accumulator */
6313   l = aopGet (AOP (IC_JTCOND (ic)), 0, FALSE);
6314   if (!IS_GB)
6315     emit2 ("push de");
6316   emit2 ("ld e,%s", l);
6317   emit2 ("ld d,!zero");
6318   jtab = newiTempLabel (NULL);
6319   spillCached ();
6320   emit2 ("ld hl,!immed!tlabel", jtab->key + 100);
6321   emit2 ("add hl,de");
6322   emit2 ("add hl,de");
6323   emit2 ("add hl,de");
6324   freeAsmop (IC_JTCOND (ic), NULL, ic);
6325   if (!IS_GB)
6326     emit2 ("pop de");
6327   emit2 ("jp !*hl");
6328   emitLabel (jtab->key + 100);
6329   /* now generate the jump labels */
6330   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab;
6331        jtab = setNextItem (IC_JTLABELS (ic)))
6332     emit2 ("jp !tlabel", jtab->key + 100);
6333 }
6334
6335 /*-----------------------------------------------------------------*/
6336 /* genCast - gen code for casting                                  */
6337 /*-----------------------------------------------------------------*/
6338 static void
6339 genCast (iCode * ic)
6340 {
6341   operand *result = IC_RESULT (ic);
6342   sym_link *ctype = operandType (IC_LEFT (ic));
6343   operand *right = IC_RIGHT (ic);
6344   int size, offset;
6345
6346   /* if they are equivalent then do nothing */
6347   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
6348     return;
6349
6350   aopOp (right, ic, FALSE, FALSE);
6351   aopOp (result, ic, FALSE, FALSE);
6352
6353   /* if the result is a bit */
6354   if (AOP_TYPE (result) == AOP_CRY)
6355     {
6356       wassertl (0, "Tried to cast to a bit");
6357     }
6358
6359   /* if they are the same size : or less */
6360   if (AOP_SIZE (result) <= AOP_SIZE (right))
6361     {
6362
6363       /* if they are in the same place */
6364       if (sameRegs (AOP (right), AOP (result)))
6365         goto release;
6366
6367       /* if they in different places then copy */
6368       size = AOP_SIZE (result);
6369       offset = 0;
6370       while (size--)
6371         {
6372           aopPut (AOP (result),
6373                   aopGet (AOP (right), offset, FALSE),
6374                   offset);
6375           offset++;
6376         }
6377       goto release;
6378     }
6379
6380   /* So we now know that the size of destination is greater
6381      than the size of the source */
6382   /* we move to result for the size of source */
6383   size = AOP_SIZE (right);
6384   offset = 0;
6385   while (size--)
6386     {
6387       aopPut (AOP (result),
6388               aopGet (AOP (right), offset, FALSE),
6389               offset);
6390       offset++;
6391     }
6392
6393   /* now depending on the sign of the destination */
6394   size = AOP_SIZE (result) - AOP_SIZE (right);
6395   /* Unsigned or not an integral type - right fill with zeros */
6396   if (SPEC_USIGN (ctype) || !IS_SPEC (ctype))
6397     {
6398       while (size--)
6399         aopPut (AOP (result), "!zero", offset++);
6400     }
6401   else
6402     {
6403       /* we need to extend the sign :{ */
6404         const char *l = aopGet (AOP (right), AOP_SIZE (right) - 1,
6405                         FALSE);
6406       _moveA (l);
6407       emit2 ("rla ");
6408       emit2 ("sbc a,a");
6409       while (size--)
6410         aopPut (AOP (result), "a", offset++);
6411     }
6412
6413 release:
6414   freeAsmop (right, NULL, ic);
6415   freeAsmop (result, NULL, ic);
6416 }
6417
6418 /*-----------------------------------------------------------------*/
6419 /* genReceive - generate code for a receive iCode                  */
6420 /*-----------------------------------------------------------------*/
6421 static void
6422 genReceive (iCode * ic)
6423 {
6424   if (isOperandInFarSpace (IC_RESULT (ic)) &&
6425       (OP_SYMBOL (IC_RESULT (ic))->isspilt ||
6426        IS_TRUE_SYMOP (IC_RESULT (ic))))
6427     {
6428       wassert (0);
6429     }
6430   else
6431     {
6432         // PENDING: HACK
6433         int size;
6434         int i;
6435
6436         aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6437         size = AOP_SIZE(IC_RESULT(ic));
6438
6439         for (i = 0; i < size; i++) {
6440             aopPut(AOP(IC_RESULT(ic)), _fReceive[_G.receiveOffset++], i);
6441         }
6442     }
6443
6444   freeAsmop (IC_RESULT (ic), NULL, ic);
6445 }
6446
6447 enum
6448   {
6449     /** Maximum number of bytes to emit per line. */
6450     DBEMIT_MAX_RUN = 8
6451   };
6452
6453 /** Context for the byte output chunker. */
6454 typedef struct
6455 {
6456   unsigned char buffer[DBEMIT_MAX_RUN];
6457   int pos;
6458 } DBEMITCTX;
6459
6460
6461 /** Flushes a byte chunker by writing out all in the buffer and
6462     reseting. 
6463 */
6464 static void
6465 _dbFlush(DBEMITCTX *self)
6466 {
6467   char line[256];
6468
6469   if (self->pos > 0)
6470     {
6471       int i;
6472       sprintf(line, ".db 0x%02X", self->buffer[0]);
6473
6474       for (i = 1; i < self->pos; i++)
6475         {
6476           sprintf(line + strlen(line), ", 0x%02X", self->buffer[i]);
6477         }
6478       emit2(line);
6479     }
6480   self->pos = 0;
6481 }
6482
6483 /** Write out another byte, buffering until a decent line is
6484     generated.
6485 */
6486 static void
6487 _dbEmit(DBEMITCTX *self, int c)
6488 {
6489   if (self->pos == DBEMIT_MAX_RUN)
6490     {
6491       _dbFlush(self);
6492     }
6493   self->buffer[self->pos++] = c;
6494 }
6495
6496 /** Context for a simple run length encoder. */
6497 typedef struct
6498 {
6499   unsigned last;
6500   unsigned char buffer[128];
6501   int pos;
6502   /** runLen may be equivalent to pos. */
6503   int runLen;
6504 } RLECTX;
6505
6506 enum
6507   {
6508     RLE_CHANGE_COST = 4,
6509     RLE_MAX_BLOCK = 127
6510   };
6511
6512 /** Flush the buffer of a run length encoder by writing out the run or
6513     data that it currently contains.
6514 */
6515 static void
6516 _rleCommit(RLECTX *self)
6517 {
6518   int i;
6519   if (self->pos != 0)
6520     {
6521       DBEMITCTX db;
6522       memset(&db, 0, sizeof(db));
6523           
6524       emit2(".db %u", self->pos);
6525       
6526       for (i = 0; i < self->pos; i++)
6527         {
6528           _dbEmit(&db, self->buffer[i]);
6529         }
6530       _dbFlush(&db);
6531     }
6532   /* Reset */
6533   self->pos = 0;
6534 }
6535
6536 /* Encoder design:
6537    Can get either a run or a block of random stuff.
6538    Only want to change state if a good run comes in or a run ends.
6539    Detecting run end is easy.
6540    Initial state?
6541
6542    Say initial state is in run, len zero, last zero.  Then if you get a
6543    few zeros then something else then a short run will be output.
6544    Seems OK.  While in run mode, keep counting.  While in random mode,
6545    keep a count of the run.  If run hits margin, output all up to run,
6546    restart, enter run mode.
6547 */
6548
6549 /** Add another byte into the run length encoder, flushing as
6550     required.  The run length encoder uses the Amiga IFF style, where
6551     a block is prefixed by its run length.  A positive length means
6552     the next n bytes pass straight through.  A negative length means
6553     that the next byte is repeated -n times.  A zero terminates the
6554     chunks.
6555 */
6556 static void
6557 _rleAppend(RLECTX *self, int c)
6558 {
6559   int i;
6560
6561   if (c != self->last)
6562     {
6563       /* The run has stopped.  See if it is worthwhile writing it out
6564          as a run.  Note that the random data comes in as runs of
6565          length one.
6566       */
6567       if (self->runLen > RLE_CHANGE_COST)
6568         {
6569           /* Yes, worthwhile. */
6570           /* Commit whatever was in the buffer. */
6571           _rleCommit(self);
6572           emit2(".db -%u,0x%02X", self->runLen, self->last);
6573         }
6574       else
6575         {
6576           /* Not worthwhile.  Append to the end of the random list. */
6577           for (i = 0; i < self->runLen; i++)
6578             {
6579               if (self->pos >= RLE_MAX_BLOCK)
6580                 {
6581                   /* Commit. */
6582                   _rleCommit(self);
6583                 }
6584               self->buffer[self->pos++] = self->last;
6585             }
6586         }
6587       self->runLen = 1;
6588       self->last = c;
6589     }
6590   else
6591     {
6592       if (self->runLen >= RLE_MAX_BLOCK)
6593         {
6594           /* Commit whatever was in the buffer. */
6595           _rleCommit(self);
6596
6597           emit2 (".db -%u,0x%02X", self->runLen, self->last);
6598           self->runLen = 0;
6599         }
6600       self->runLen++;
6601     }
6602 }
6603
6604 static void
6605 _rleFlush(RLECTX *self)
6606 {
6607   _rleAppend(self, -1);
6608   _rleCommit(self);
6609   self->pos = 0;
6610   self->last = 0;
6611   self->runLen = 0;
6612 }
6613
6614 /** genArrayInit - Special code for initialising an array with constant
6615    data.
6616 */
6617 static void
6618 genArrayInit (iCode * ic)
6619 {
6620   literalList *iLoop;
6621   int         ix;
6622   int         elementSize = 0, eIndex, i;
6623   unsigned    val, lastVal;
6624   sym_link    *type;
6625   RLECTX      rle;
6626
6627   memset(&rle, 0, sizeof(rle));
6628
6629   aopOp (IC_LEFT(ic), ic, FALSE, FALSE);
6630
6631   _saveRegsForCall(ic, 0);
6632
6633   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6634   emit2 ("call __initrleblock");
6635     
6636   type = operandType(IC_LEFT(ic));
6637     
6638   if (type && type->next)
6639     {
6640       elementSize = getSize(type->next);
6641     }
6642   else
6643     {
6644       wassertl (0, "Can't determine element size in genArrayInit.");
6645     }
6646
6647   iLoop = IC_ARRAYILIST(ic);
6648   lastVal = (unsigned)-1;
6649
6650   /* Feed all the bytes into the run length encoder which will handle
6651      the actual output.
6652      This works well for mixed char data, and for random int and long
6653      data.
6654   */
6655   while (iLoop)
6656     {
6657       ix = iLoop->count;
6658
6659       if (ix != 0)
6660         {
6661           for (i = 0; i < ix; i++)
6662             {
6663               for (eIndex = 0; eIndex < elementSize; eIndex++)
6664                 {
6665                   val = (((int)iLoop->literalValue) >> (eIndex * 8)) & 0xff;
6666                   _rleAppend(&rle, val);
6667                 }
6668             }
6669         }
6670         
6671       iLoop = iLoop->next;
6672     }
6673
6674   _rleFlush(&rle);
6675   /* Mark the end of the run. */
6676   emit2(".db 0");
6677
6678   _restoreRegsAfterCall();
6679
6680   spillCached ();
6681
6682   freeAsmop (IC_LEFT(ic), NULL, ic);
6683 }
6684
6685 static void
6686 _swap (PAIR_ID one, PAIR_ID two)
6687 {
6688   if ((one == PAIR_DE && two == PAIR_HL) || (one == PAIR_HL && two == PAIR_DE))
6689     {
6690       emit2 ("ex de,hl");
6691     }
6692   else
6693     {
6694       emit2 ("ld a,%s", _pairs[one].l);
6695       emit2 ("ld %s,%s", _pairs[one].l, _pairs[two].l);
6696       emit2 ("ld %s,a", _pairs[two].l);
6697       emit2 ("ld a,%s", _pairs[one].h);
6698       emit2 ("ld %s,%s", _pairs[one].h, _pairs[two].h);
6699       emit2 ("ld %s,a", _pairs[two].h);
6700     }
6701 }
6702
6703 /* The problem is that we may have all three pairs used and they may
6704    be needed in a different order.
6705
6706    Note: Have ex de,hl
6707
6708    Combinations:
6709      hl = hl            => unity, fine
6710      bc = bc
6711      de = de
6712
6713      hl = hl            hl = hl, swap de <=> bc
6714      bc = de
6715      de = bc
6716
6717      hl = bc            Worst case
6718      bc = de
6719      de = hl
6720      
6721      hl = bc            de = de, swap bc <=> hl
6722      bc = hl
6723      de = de
6724
6725      hl = de            Worst case
6726      bc = hl
6727      de = bc
6728
6729      hl = de            bc = bc, swap hl <=> de
6730      bc = bc
6731      de = hl
6732
6733    Break it down into:
6734     * Any pair = pair are done last
6735     * Any pair = iTemp are done last
6736     * Any swaps can be done any time
6737
6738    A worst case:
6739     push p1
6740     p1 = p2
6741     p2 = p3
6742     pop  p3
6743
6744    So how do we detect the cases?
6745    How about a 3x3 matrix?
6746         source
6747    dest x x x x
6748         x x x x
6749         x x x x (Fourth for iTemp/other)
6750
6751    First determin which mode to use by counting the number of unity and
6752    iTemp assigns.
6753      Three - any order
6754      Two - Assign the pair first, then the rest
6755      One - Swap the two, then the rest
6756      Zero - Worst case.
6757 */
6758 static void
6759 setupForBuiltin3 (iCode *ic, int nparams, operand **pparams)
6760 {
6761   PAIR_ID ids[NUM_PAIRS][NUM_PAIRS];
6762   PAIR_ID dest[3] = {
6763     PAIR_BC, PAIR_HL, PAIR_DE
6764   };
6765   int i, j, nunity = 0;
6766   memset (ids, PAIR_INVALID, sizeof (ids));
6767
6768   /* Sanity checks */
6769   wassert (nparams == 3);
6770
6771   /* First save everything that needs to be saved. */
6772   _saveRegsForCall (ic, 0);
6773
6774   /* Loading HL first means that DE is always fine. */
6775   for (i = 0; i < nparams; i++)
6776     {
6777       aopOp (pparams[i], ic, FALSE, FALSE);
6778       ids[dest[i]][getPairId (AOP (pparams[i]))] = TRUE;
6779     }
6780
6781   /* Count the number of unity or iTemp assigns. */
6782   for (i = 0; i < 3; i++) 
6783     {
6784       if (ids[dest[i]][dest[i]] == TRUE || ids[dest[i]][PAIR_INVALID] == TRUE)
6785         {
6786           nunity++;
6787         }
6788     }
6789
6790   if (nunity == 3)
6791     {
6792       /* Any order, fall through. */
6793     }
6794   else if (nunity == 2)
6795     {
6796       /* One is assigned.  Pull it out and assign. */
6797       for (i = 0; i < 3; i++)
6798         {
6799           for (j = 0; j < NUM_PAIRS; j++)
6800             {
6801               if (ids[dest[i]][j] == TRUE)
6802                 {
6803                   /* Found it.  See if it's the right one. */
6804                   if (j == PAIR_INVALID || j == dest[i])
6805                     {
6806                       /* Keep looking. */
6807                     }
6808                   else
6809                     {
6810                       fetchPair(dest[i], AOP (pparams[i]));
6811                       goto done;
6812                     }
6813                 }
6814             }
6815         }
6816     }
6817   else if (nunity == 1)
6818     {
6819       /* Find the pairs to swap. */
6820       for (i = 0; i < 3; i++)
6821         {
6822           for (j = 0; j < NUM_PAIRS; j++)
6823             {
6824               if (ids[dest[i]][j] == TRUE)
6825                 {
6826                   if (j == PAIR_INVALID || j == dest[i])
6827                     {
6828                       /* Keep looking. */
6829                     }
6830                   else
6831                     {
6832                       _swap (j, dest[i]);
6833                       goto done;
6834                     }
6835                 }
6836             }
6837         }
6838     }
6839   else
6840     {
6841       int next = getPairId (AOP (pparams[0]));
6842       emit2 ("push %s", _pairs[next].name);
6843
6844       if (next == dest[1])
6845         {
6846           fetchPair (dest[1], AOP (pparams[1]));
6847           fetchPair (dest[2], AOP (pparams[2]));
6848         }
6849       else
6850         {
6851           fetchPair (dest[2], AOP (pparams[2]));
6852           fetchPair (dest[1], AOP (pparams[1]));
6853         }
6854       emit2 ("pop %s", _pairs[dest[0]].name);
6855     }
6856  done:
6857   /* Finally pull out all of the iTemps */
6858   for (i = 0; i < 3; i++)
6859     {
6860       if (ids[dest[i]][PAIR_INVALID] == 1)
6861         {
6862           fetchPair (dest[i], AOP (pparams[i]));
6863         }
6864     }
6865 }
6866
6867 static void
6868 genBuiltInStrcpy (iCode *ic, int nParams, operand **pparams)
6869 {
6870   operand *from, *to;
6871   symbol *label;
6872   bool deInUse;
6873
6874   wassertl (nParams == 2, "Built-in strcpy must have two parameters");
6875   to = pparams[0];
6876   from = pparams[1];
6877
6878   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6879
6880   setupForBuiltin3 (ic, nParams, pparams);
6881
6882   label = newiTempLabel(NULL);
6883
6884   emitLabel (label->key);
6885   emit2 ("ld a,(hl)");
6886   emit2 ("ldi");
6887   emit2 ("or a");
6888   emit2 ("!shortjp nz,!tlabel ; 1", label->key);
6889
6890   freeAsmop (from, NULL, ic->next);
6891   freeAsmop (to, NULL, ic);
6892 }
6893
6894 static void
6895 genBuiltInMemcpy (iCode *ic, int nParams, operand **pparams)
6896 {
6897   operand *from, *to, *count;
6898   symbol *label;
6899   bool deInUse;
6900   iCode *pcall;
6901
6902   wassertl (nParams == 3, "Built-in memcpy must have two parameters");
6903   to = pparams[2];
6904   from = pparams[1];
6905   count = pparams[0];
6906
6907   deInUse = bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue(ic->rMask, E_IDX);
6908
6909   setupForBuiltin3 (ic, nParams, pparams);
6910
6911   emit2 ("ldir");
6912
6913   freeAsmop (count, NULL, ic->next->next);
6914   freeAsmop (from, NULL, ic);
6915
6916   _restoreRegsAfterCall();
6917
6918   /* if we need assign a result value */
6919   if ((IS_ITEMP (IC_RESULT (ic)) &&
6920        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
6921         OP_SYMBOL (IC_RESULT (ic))->spildir)) ||
6922       IS_TRUE_SYMOP (IC_RESULT (ic)))
6923     {
6924       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
6925       movLeft2ResultLong (to, 0, IC_RESULT (ic), 0, 0, 2);
6926       freeAsmop (IC_RESULT (ic), NULL, ic);
6927     }
6928
6929   freeAsmop (to, NULL, ic->next);
6930 }
6931
6932 /*-----------------------------------------------------------------*/
6933 /* genBuiltIn - calls the appropriate function to  generating code */
6934 /* for a built in function                                         */
6935 /*-----------------------------------------------------------------*/
6936 static void genBuiltIn (iCode *ic)
6937 {
6938     operand *bi_parms[MAX_BUILTIN_ARGS];
6939     int nbi_parms;
6940     iCode *bi_iCode;
6941     symbol *bif;
6942
6943     /* get all the arguments for a built in function */
6944     bi_iCode = getBuiltinParms(ic,&nbi_parms,bi_parms);
6945
6946     /* which function is it */
6947     bif = OP_SYMBOL(IC_LEFT(bi_iCode));
6948
6949     if (strcmp(bif->name,"__builtin_strcpy")==0) 
6950       {
6951         genBuiltInStrcpy(bi_iCode, nbi_parms, bi_parms);
6952       } 
6953     else if (strcmp(bif->name,"__builtin_memcpy")==0) 
6954       {
6955         genBuiltInMemcpy(bi_iCode, nbi_parms, bi_parms);
6956       } 
6957     else 
6958       {
6959         wassertl (0, "Unknown builtin function encountered");
6960       }
6961 }
6962
6963 /*-----------------------------------------------------------------*/
6964 /* genZ80Code - generate code for Z80 based controllers            */
6965 /*-----------------------------------------------------------------*/
6966 void
6967 genZ80Code (iCode * lic)
6968 {
6969   iCode *ic;
6970   int cln = 0;
6971
6972   /* Hack */
6973   if (IS_GB)
6974     {
6975       _fReturn = _gbz80_return;
6976       _fTmp = _gbz80_return;
6977     }
6978   else
6979     {
6980       _fReturn = _z80_return;
6981       _fTmp = _z80_return;
6982     }
6983
6984   _G.lines.head = _G.lines.current = NULL;
6985
6986   for (ic = lic; ic; ic = ic->next)
6987     {
6988
6989       if (cln != ic->lineno)
6990         {
6991           emit2 ("; %s %d", ic->filename, ic->lineno);
6992           cln = ic->lineno;
6993         }
6994       /* if the result is marked as
6995          spilt and rematerializable or code for
6996          this has already been generated then
6997          do nothing */
6998       if (resultRemat (ic) || ic->generated)
6999         continue;
7000
7001       /* depending on the operation */
7002       switch (ic->op)
7003         {
7004         case '!':
7005           emitDebug ("; genNot");
7006           genNot (ic);
7007           break;
7008
7009         case '~':
7010           emitDebug ("; genCpl");
7011           genCpl (ic);
7012           break;
7013
7014         case UNARYMINUS:
7015           emitDebug ("; genUminus");
7016           genUminus (ic);
7017           break;
7018
7019         case IPUSH:
7020           emitDebug ("; genIpush");
7021           genIpush (ic);
7022           break;
7023
7024         case IPOP:
7025           /* IPOP happens only when trying to restore a
7026              spilt live range, if there is an ifx statement
7027              following this pop then the if statement might
7028              be using some of the registers being popped which
7029              would destory the contents of the register so
7030              we need to check for this condition and handle it */
7031           if (ic->next &&
7032               ic->next->op == IFX &&
7033               regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
7034             {
7035               emitDebug ("; genIfx");
7036               genIfx (ic->next, ic);
7037             }
7038           else
7039             {
7040               emitDebug ("; genIpop");
7041               genIpop (ic);
7042             }
7043           break;
7044
7045         case CALL:
7046           emitDebug ("; genCall");
7047           genCall (ic);
7048           break;
7049
7050         case PCALL:
7051           emitDebug ("; genPcall");
7052           genPcall (ic);
7053           break;
7054
7055         case FUNCTION:
7056           emitDebug ("; genFunction");
7057           genFunction (ic);
7058           break;
7059
7060         case ENDFUNCTION:
7061           emitDebug ("; genEndFunction");
7062           genEndFunction (ic);
7063           break;
7064
7065         case RETURN:
7066           emitDebug ("; genRet");
7067           genRet (ic);
7068           break;
7069
7070         case LABEL:
7071           emitDebug ("; genLabel");
7072           genLabel (ic);
7073           break;
7074
7075         case GOTO:
7076           emitDebug ("; genGoto");
7077           genGoto (ic);
7078           break;
7079
7080         case '+':
7081           emitDebug ("; genPlus");
7082           genPlus (ic);
7083           break;
7084
7085         case '-':
7086           emitDebug ("; genMinus");
7087           genMinus (ic);
7088           break;
7089
7090         case '*':
7091           emitDebug ("; genMult");
7092           genMult (ic);
7093           break;
7094
7095         case '/':
7096           emitDebug ("; genDiv");
7097           genDiv (ic);
7098           break;
7099
7100         case '%':
7101           emitDebug ("; genMod");
7102           genMod (ic);
7103           break;
7104
7105         case '>':
7106           emitDebug ("; genCmpGt");
7107           genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
7108           break;
7109
7110         case '<':
7111           emitDebug ("; genCmpLt");
7112           genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
7113           break;
7114
7115         case LE_OP:
7116         case GE_OP:
7117         case NE_OP:
7118
7119           /* note these two are xlated by algebraic equivalence
7120              during parsing SDCC.y */
7121           werror (E_INTERNAL_ERROR, __FILE__, __LINE__,
7122                   "got '>=' or '<=' shouldn't have come here");
7123           break;
7124
7125         case EQ_OP:
7126           emitDebug ("; genCmpEq");
7127           genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
7128           break;
7129
7130         case AND_OP:
7131           emitDebug ("; genAndOp");
7132           genAndOp (ic);
7133           break;
7134
7135         case OR_OP:
7136           emitDebug ("; genOrOp");
7137           genOrOp (ic);
7138           break;
7139
7140         case '^':
7141           emitDebug ("; genXor");
7142           genXor (ic, ifxForOp (IC_RESULT (ic), ic));
7143           break;
7144
7145         case '|':
7146           emitDebug ("; genOr");
7147           genOr (ic, ifxForOp (IC_RESULT (ic), ic));
7148           break;
7149
7150         case BITWISEAND:
7151           emitDebug ("; genAnd");
7152           genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
7153           break;
7154
7155         case INLINEASM:
7156           emitDebug ("; genInline");
7157           genInline (ic);
7158           break;
7159
7160         case RRC:
7161           emitDebug ("; genRRC");
7162           genRRC (ic);
7163           break;
7164
7165         case RLC:
7166           emitDebug ("; genRLC");
7167           genRLC (ic);
7168           break;
7169
7170         case GETHBIT:
7171           emitDebug ("; genGetHBIT");
7172           genGetHbit (ic);
7173           break;
7174
7175         case LEFT_OP:
7176           emitDebug ("; genLeftShift");
7177           genLeftShift (ic);
7178           break;
7179
7180         case RIGHT_OP:
7181           emitDebug ("; genRightShift");
7182           genRightShift (ic);
7183           break;
7184
7185         case GET_VALUE_AT_ADDRESS:
7186           emitDebug ("; genPointerGet");
7187           genPointerGet (ic);
7188           break;
7189
7190         case '=':
7191
7192           if (POINTER_SET (ic))
7193             {
7194               emitDebug ("; genAssign (pointer)");
7195               genPointerSet (ic);
7196             }
7197           else
7198             {
7199               emitDebug ("; genAssign");
7200               genAssign (ic);
7201             }
7202           break;
7203
7204         case IFX:
7205           emitDebug ("; genIfx");
7206           genIfx (ic, NULL);
7207           break;
7208
7209         case ADDRESS_OF:
7210           emitDebug ("; genAddrOf");
7211           genAddrOf (ic);
7212           break;
7213
7214         case JUMPTABLE:
7215           emitDebug ("; genJumpTab");
7216           genJumpTab (ic);
7217           break;
7218
7219         case CAST:
7220           emitDebug ("; genCast");
7221           genCast (ic);
7222           break;
7223
7224         case RECEIVE:
7225           emitDebug ("; genReceive");
7226           genReceive (ic);
7227           break;
7228
7229         case SEND:
7230           if (ic->builtinSEND)
7231             {
7232               emitDebug ("; genBuiltIn");
7233               genBuiltIn(ic);
7234             }
7235           else
7236             {
7237               emitDebug ("; addSet");
7238               addSet (&_G.sendSet, ic);
7239             }
7240           break;
7241
7242         case ARRAYINIT:
7243           emitDebug ("; genArrayInit");
7244           genArrayInit(ic);
7245           break;
7246             
7247         default:
7248           ic = ic;
7249         }
7250     }
7251
7252
7253   /* now we are ready to call the
7254      peep hole optimizer */
7255   if (!options.nopeep)
7256     peepHole (&_G.lines.head);
7257
7258   /* This is unfortunate */
7259   /* now do the actual printing */
7260   {
7261     FILE *fp = codeOutFile;
7262     if (isInHome () && codeOutFile == code->oFile)
7263       codeOutFile = home->oFile;
7264     printLine (_G.lines.head, codeOutFile);
7265     if (_G.flushStatics)
7266       {
7267         flushStatics ();
7268         _G.flushStatics = 0;
7269       }
7270     codeOutFile = fp;
7271   }
7272
7273   freeTrace(&_G.lines.trace);
7274   freeTrace(&_G.trace.aops);
7275 }
7276
7277 /*
7278   Attic
7279 static int
7280 _isPairUsed (iCode * ic, PAIR_ID pairId)
7281 {
7282   int ret = 0;
7283   switch (pairId)
7284     {
7285     case PAIR_DE:
7286       if (bitVectBitValue (ic->rMask, D_IDX))
7287         ret++;
7288       if (bitVectBitValue (ic->rMask, E_IDX))
7289         ret++;
7290       break;
7291     default:
7292       wassert (0);
7293     }
7294   return ret;
7295 }
7296
7297 static char *
7298 fetchLitSpecial (asmop * aop, bool negate, bool xor)
7299 {
7300   unsigned long v;
7301   value *val = aop->aopu.aop_lit;
7302
7303   wassert (aop->type == AOP_LIT);
7304   wassert (!IS_FLOAT (val->type));
7305
7306   v = (unsigned long) floatFromVal (val);
7307
7308   if (xor)
7309     v ^= 0x8000;
7310   if (negate)
7311     v = 0-v;
7312   v &= 0xFFFF;
7313
7314   tsprintf (buffer, "!immedword", v);
7315   return traceAlloc(&_G.trace.aops, Safe_strdup (buffer));
7316 }
7317
7318
7319 */