1 /*-------------------------------------------------------------------------
2   gen.c - code generator for Z80 / Z180 / GBZ80.
3 
4   Copyright (C) 1998, Sandeep Dutta . sandeep.dutta@usa.net
5   Copyright (C) 1999, Jean-Louis VERN.jlvern@writeme.com
6   Copyright (C) 2000, Michael Hope <michaelh@juju.net.nz>
7   Copyright (C) 2011-2018, Philipp Klaus Krause pkk@spth.de, philipp@informatik.uni-frankfurt.de)
8 
9   This program is free software; you can redistribute it and/or modify it
10   under the terms of the GNU General Public License as published by the
11   Free Software Foundation; either version 2, or (at your option) any
12   later version.
13 
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18 
19   You should have received a copy of the GNU General Public License
20   along with this program; if not, write to the Free Software
21   Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 -------------------------------------------------------------------------*/
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 
29 #include "z80.h"
30 #include "gen.h"
31 #include "dbuf_string.h"
32 
33 /* This is the down and dirty file with all kinds of kludgy & hacky
34    stuff. This is what it is all about CODE GENERATION for a specific MCU.
35    Some of the routines may be reusable, will have to see */
36 
37 /* Z80 calling convention description.
38    Parameters are passed right to left.  As the stack grows downwards,
39    the parameters are arranged in left to right in memory.
40 
41    Everything is caller saves. i.e. the caller must save any registers
42    that it wants to preserve over the call, except for ix, which is callee saves.
43    GB: The return value is returned in DEHL.  DE is normally used as a
44    working register pair.  Caller saves allows it to be used for a
45    return value.
46    va args functions do not use register parameters.  All arguments
47    are passed on the stack.
48    IX is used as an index register to the top of the local variable
49    area.  ix-0 is the top most local variable.
50 */
51 
52 enum
53 {
54   /* Set to enable debugging trace statements in the output assembly code. */
55   DISABLE_DEBUG = 0
56 };
57 
58 // #define DEBUG_DRY_COST
59 
60 extern struct dbuf_s *codeOutBuf;
61 
62 enum
63 {
64   INT8MIN = -128,
65   INT8MAX = 127
66 };
67 
68 /** Enum covering all the possible register pairs.
69  */
70 typedef enum
71 {
72   PAIR_INVALID,
73   PAIR_AF,
74   PAIR_BC,
75   PAIR_DE,
76   PAIR_HL,
77   PAIR_IY,
78   PAIR_IX,
79   NUM_PAIRS
80 } PAIR_ID;
81 
82 static struct
83 {
84   const char *name;
85   const char *l;
86   const char *h;
87   int l_idx;
88   int h_idx;
89 } _pairs[NUM_PAIRS] =
90 {
91   {
92     "??1", "?2", "?3", -1, -1
93   },
94   {
95     "af", "f", "a", -1, A_IDX
96   },
97   {
98     "bc", "c", "b", C_IDX, B_IDX
99   },
100   {
101     "de", "e", "d", E_IDX, D_IDX
102   },
103   {
104     "hl", "l", "h", L_IDX, H_IDX
105   },
106   {
107     "iy", "iyl", "iyh", IYL_IDX, IYH_IDX
108   },
109   {
110     "ix", "ixl", "ixh", -1, -1
111   }
112 };
113 
114 enum
115 {
116   LSB,
117   MSB16,
118   MSB24,
119   MSB32
120 };
121 
122 enum asminst
123 {
124   A_ADD,
125   A_ADC,
126   A_AND,
127   A_CP,
128   A_CPL,
129   A_DEC,
130   A_INC,
131   A_LD,
132   A_NEG,
133   A_OR,
134   A_RL,
135   A_RLA,
136   A_RLC,
137   A_RLCA,
138   A_RR,
139   A_RRA,
140   A_RRC,
141   A_RRCA,
142   A_SBC,
143   A_SLA,
144   A_SRA,
145   A_SRL,
146   A_SUB,
147   A_XOR,
148   A_SWAP
149 };
150 
151 static const char *asminstnames[] =
152 {
153   "add",
154   "adc",
155   "and",
156   "cp",
157   "cpl",
158   "dec",
159   "inc",
160   "ld",
161   "neg",
162   "or",
163   "rl",
164   "rla",
165   "rlc",
166   "rlca",
167   "rr",
168   "rra",
169   "rrc",
170   "rrca",
171   "sbc",
172   "sla",
173   "sra",
174   "srl",
175   "sub",
176   "xor",
177   "swap"
178 };
179 
180 /** Code generator persistent data.
181  */
182 static struct
183 {
184   /** Used to optimise setting up of a pair by remembering what it
185       contains and adjusting instead of reloading where possible.
186   */
187   struct
188   {
189     AOP_TYPE last_type;
190     const char *base;
191     int offset;
192   } pairs[NUM_PAIRS];
193   struct
194   {
195 //    int last;
196     int pushed;
197     int param_offset;
198     int offset;
199     int pushedHL;
200     int pushedBC;
201     int pushedDE;
202     int pushedIY;
203   } stack;
204 
205   struct
206   {
207     int pushedBC;
208     int pushedDE;
209   } calleeSaves;
210 
211   bool omitFramePtr;
212   int frameId;
213   int receiveOffset;
214   bool flushStatics;
215   bool in_home;
216   const char *lastFunctionName;
217   iCode *current_iCode;
218   bool preserveCarry;
219 
220   set *sendSet;
221 
222   struct
223   {
224     /** TRUE if the registers have already been saved. */
225     bool saved;
226   } saves;
227 
228   struct
229   {
230     allocTrace trace;
231   } lines;
232 
233   struct
234   {
235     allocTrace aops;
236   } trace;
237 } _G;
238 
239 bool z80_regs_used_as_parms_in_calls_from_current_function[IYH_IDX + 1];
240 bool z80_symmParm_in_calls_from_current_function;
241 bool z80_regs_preserved_in_calls_from_current_function[IYH_IDX + 1];
242 
243 static const char *aopGet (asmop *aop, int offset, bool bit16);
244 
245 static struct asmop asmop_a, asmop_b, asmop_c, asmop_d, asmop_e, asmop_h, asmop_l, asmop_iyh, asmop_iyl, asmop_zero, asmop_one, asmop_return;
246 static struct asmop *const ASMOP_A = &asmop_a;
247 static struct asmop *const ASMOP_B = &asmop_b;
248 static struct asmop *const ASMOP_C = &asmop_c;
249 static struct asmop *const ASMOP_D = &asmop_d;
250 static struct asmop *const ASMOP_E = &asmop_e;
251 static struct asmop *const ASMOP_H = &asmop_h;
252 static struct asmop *const ASMOP_L = &asmop_l;
253 static struct asmop *const ASMOP_IYH = &asmop_iyh;
254 static struct asmop *const ASMOP_IYL = &asmop_iyl;
255 static struct asmop *const ASMOP_ZERO = &asmop_zero;
256 static struct asmop *const ASMOP_ONE = &asmop_one;
257 static struct asmop *const ASMOP_RETURN = &asmop_return;
258 
259 static asmop *asmopregs[] = { &asmop_a, &asmop_c, &asmop_b, &asmop_e, &asmop_d, &asmop_l, &asmop_h, &asmop_iyl, &asmop_iyh };
260 
261 void
z80_init_asmops(void)262 z80_init_asmops (void)
263 {
264   asmop_a.type = AOP_REG;
265   asmop_a.size = 1;
266   asmop_a.aopu.aop_reg[0] = regsZ80 + A_IDX;
267   memset (asmop_a.regs, -1, 9);
268   asmop_a.regs[A_IDX] = 0;
269   asmop_b.type = AOP_REG;
270   asmop_b.size = 1;
271   asmop_b.aopu.aop_reg[0] = regsZ80 + B_IDX;
272   memset (asmop_b.regs, -1, 9);
273   asmop_b.regs[B_IDX] = 0;
274   asmop_c.type = AOP_REG;
275   asmop_c.size = 1;
276   asmop_c.aopu.aop_reg[0] = regsZ80 + C_IDX;
277   memset (asmop_c.regs, -1, 9);
278   asmop_c.regs[C_IDX] = 0;
279   asmop_d.type = AOP_REG;
280   asmop_d.size = 1;
281   asmop_d.aopu.aop_reg[0] = regsZ80 + D_IDX;
282   memset (asmop_d.regs, -1, 9);
283   asmop_d.regs[D_IDX] = 0;
284   asmop_e.type = AOP_REG;
285   asmop_e.size = 1;
286   asmop_e.aopu.aop_reg[0] = regsZ80 + E_IDX;
287   memset (asmop_e.regs, -1, 9);
288   asmop_e.regs[E_IDX] = 0;
289   asmop_h.type = AOP_REG;
290   asmop_h.size = 1;
291   asmop_h.aopu.aop_reg[0] = regsZ80 + H_IDX;
292   memset (asmop_h.regs, -1, 9);
293   asmop_h.regs[H_IDX] = 0;
294   asmop_l.type = AOP_REG;
295   asmop_l.size = 1;
296   asmop_l.aopu.aop_reg[0] = regsZ80 + L_IDX;
297   memset (asmop_l.regs, -1, 9);
298   asmop_l.regs[L_IDX] = 0;
299   asmop_iyh.type = AOP_REG;
300   asmop_iyh.size = 1;
301   asmop_iyh.aopu.aop_reg[0] = regsZ80 + IYH_IDX;
302   memset (asmop_iyh.regs, -1, 9);
303   asmop_iyh.regs[IYH_IDX] = 0;
304   asmop_iyl.type = AOP_REG;
305   asmop_iyl.size = 1;
306   asmop_iyl.aopu.aop_reg[0] = regsZ80 + IYL_IDX;
307   memset (asmop_iyl.regs, -1, 9);
308   asmop_iyl.regs[IYL_IDX] = 0;
309 
310   /*asmop_hl.type = AOP_REG;
311   asmop_hl.size = 2;
312   asmop_hl.aopu.aop_reg[0] = regsZ80 + L_IDX;
313   asmop_hl.aopu.aop_reg[1] = regsZ80 + H_IDX;
314   memset (asmop_hl.regs, -1, 9);
315   asmop_hl.regs[L_IDX] = 0;
316   asmop_hl.regs[H_IDX] = 1;*/
317 
318   asmop_zero.type = AOP_LIT;
319   asmop_zero.aopu.aop_lit = constVal ("0");
320   asmop_zero.size = 1;
321   memset (asmop_zero.regs, -1, 9);
322 
323   asmop_one.type = AOP_LIT;
324   asmop_one.aopu.aop_lit = constVal ("1");
325   asmop_one.size = 1;
326   memset (asmop_one.regs, -1, 9);
327 
328   asmop_return.type = AOP_REG;
329   asmop_return.size = 4;
330   memset (asmop_return.regs, -1, 9);
331   if (IS_GB)
332     {
333       asmop_return.aopu.aop_reg[0] = regsZ80 + E_IDX;
334       asmop_return.regs[E_IDX] = 0;
335       asmop_return.aopu.aop_reg[1] = regsZ80 + D_IDX;
336       asmop_return.regs[D_IDX] = 1;
337       asmop_return.aopu.aop_reg[2] = regsZ80 + L_IDX;
338       asmop_return.regs[L_IDX] = 2;
339       asmop_return.aopu.aop_reg[3] = regsZ80 + H_IDX;
340       asmop_return.regs[H_IDX] = 2;
341     }
342   else
343     {
344       asmop_return.aopu.aop_reg[0] = regsZ80 + L_IDX;
345       asmop_return.regs[L_IDX] = 0;
346       asmop_return.aopu.aop_reg[1] = regsZ80 + H_IDX;
347       asmop_return.regs[H_IDX] = 1;
348       asmop_return.aopu.aop_reg[2] = regsZ80 + E_IDX;
349       asmop_return.regs[E_IDX] = 2;
350       asmop_return.aopu.aop_reg[3] = regsZ80 + D_IDX;
351       asmop_return.regs[D_IDX] = 3;
352     }
353 }
354 
355 static bool regalloc_dry_run;
356 static unsigned int regalloc_dry_run_cost;
357 
358 static void
cost(unsigned int bytes,unsigned int cycles)359 cost(unsigned int bytes, unsigned int cycles)
360 {
361   regalloc_dry_run_cost += bytes;
362 }
363 
364 static void
cost2(unsigned int bytes,unsigned int cycles_z80,unsigned int cycles_z180,unsigned int cycles_r2k,unsigned int cycles_gbz80,unsigned int cycles_tlcs90,unsigned int cycles_ez80_z80)365 cost2(unsigned int bytes, unsigned int cycles_z80, unsigned int cycles_z180, unsigned int cycles_r2k, unsigned int cycles_gbz80, unsigned int cycles_tlcs90, unsigned int cycles_ez80_z80)
366 {
367   regalloc_dry_run_cost += bytes;
368 }
369 
370 /*-----------------------------------------------------------------*/
371 /* aopRS - asmop in register or on stack                           */
372 /*-----------------------------------------------------------------*/
373 static bool
aopRS(const asmop * aop)374 aopRS (const asmop *aop)
375 {
376   return (aop->type == AOP_REG || aop->type == AOP_STK || aop->type == AOP_EXSTK);
377 }
378 
379 /*-----------------------------------------------------------------*/
380 /* aopIsLitVal - asmop from offset is val                          */
381 /*-----------------------------------------------------------------*/
382 static bool
aopIsLitVal(const asmop * aop,int offset,int size,unsigned long long int val)383 aopIsLitVal (const asmop *aop, int offset, int size, unsigned long long int val)
384 {
385   wassert (size <= sizeof (unsigned long long int)); // Make sure we are not testing outside of argument val.
386 
387   for(; size; size--, offset++)
388     {
389       unsigned char b = val & 0xff;
390       val >>= 8;
391 
392       // Leading zeroes
393       if (aop->size <= offset && !b)
394         continue;
395 
396       if (aop->type != AOP_LIT)
397         return (FALSE);
398 
399       if (byteOfVal (aop->aopu.aop_lit, offset) != b)
400         return (FALSE);
401     }
402 
403   return (TRUE);
404 }
405 
406 /*-----------------------------------------------------------------*/
407 /* aopInReg - asmop from offset in the register                    */
408 /*-----------------------------------------------------------------*/
409 static inline bool
aopInReg(const asmop * aop,int offset,short rIdx)410 aopInReg (const asmop *aop, int offset, short rIdx)
411 {
412   if (!(aop->type == AOP_REG))
413     return (false);
414 
415   if (offset >= aop->size || offset < 0)
416     return (false);
417 
418   if (rIdx == IY_IDX)
419     return (aopInReg (aop, offset, IYL_IDX) && aopInReg (aop, offset + 1, IYH_IDX));
420   if (rIdx == BC_IDX)
421     return (aopInReg (aop, offset, C_IDX) && aopInReg (aop, offset + 1, B_IDX));
422   if (rIdx == DE_IDX)
423     return (aopInReg (aop, offset, E_IDX) && aopInReg (aop, offset + 1, D_IDX));
424   if (rIdx == HL_IDX)
425     return (aopInReg (aop, offset, L_IDX) && aopInReg (aop, offset + 1, H_IDX));
426 
427   return (aop->aopu.aop_reg[offset]->rIdx == rIdx);
428 }
429 
430 /*-----------------------------------------------------------------*/
431 /* aopOnStack - asmop from offset on stack in consecutive memory   */
432 /*-----------------------------------------------------------------*/
433 static bool
aopOnStack(const asmop * aop,int offset,int size)434 aopOnStack (const asmop *aop, int offset, int size)
435 {
436   if (!(aop->type == AOP_STK || aop->type == AOP_EXSTK))
437     return (false);
438 
439   if (offset + size > aop->size)
440     return (false);
441 
442   return (true);
443 }
444 
445 /* WARNING: This function is dangerous to use. It works literally:
446    It will return true if ic the the last use of op, even if ic might
447    be executed again, e.g. due to a loop. Most of the time you will want
448    to use isPairDead(), or ic->rSurv instead of this function. */
449 static bool
isLastUse(const iCode * ic,operand * op)450 isLastUse (const iCode * ic, operand * op)
451 {
452   bitVect *uses = bitVectCopy (OP_USES (op));
453 
454   while (!bitVectIsZero (uses))
455     {
456       if (bitVectFirstBit (uses) == ic->key)
457         {
458           if (bitVectnBitsOn (uses) == 1)
459             {
460               return TRUE;
461             }
462           else
463             {
464               return FALSE;
465             }
466         }
467       bitVectUnSetBit (uses, bitVectFirstBit (uses));
468     }
469 
470   return FALSE;
471 }
472 
473 static PAIR_ID
_getTempPairId(void)474 _getTempPairId (void)
475 {
476   if (IS_GB)
477     {
478       return PAIR_DE;
479     }
480   else
481     {
482       return PAIR_HL;
483     }
484 }
485 
486 static const char *
_getTempPairName(void)487 _getTempPairName (void)
488 {
489   return _pairs[_getTempPairId ()].name;
490 }
491 
492 static bool
isPairInUse(PAIR_ID id,const iCode * ic)493 isPairInUse (PAIR_ID id, const iCode * ic)
494 {
495   if (id == PAIR_DE)
496     {
497       return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue (ic->rMask, E_IDX);
498     }
499   else if (id == PAIR_BC)
500     {
501       return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue (ic->rMask, C_IDX);
502     }
503   else
504     {
505       wassertl (0, "Only implemented for DE and BC");
506       return TRUE;
507     }
508 }
509 
510 static bool
isPairDead(PAIR_ID id,const iCode * ic)511 isPairDead (PAIR_ID id, const iCode * ic)
512 {
513   const bitVect *r = (!options.oldralloc ? ic->rSurv :
514                       (POINTER_SET (ic) ? ic->rMask :
515                        (bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT (ic))))));
516 
517   if (id == PAIR_DE)
518     return !(bitVectBitValue (r, D_IDX) || bitVectBitValue (r, E_IDX));
519   else if (id == PAIR_BC)
520     return !(bitVectBitValue (r, B_IDX) || bitVectBitValue (r, C_IDX));
521   else if (id == PAIR_HL)
522     return !(bitVectBitValue (r, H_IDX) || bitVectBitValue (r, L_IDX));
523   else if (id == PAIR_IY)
524     return !(bitVectBitValue (r, IYH_IDX) || bitVectBitValue (r, IYL_IDX));
525   else
526     {
527       wassertl (0, "Only implemented for DE, BC, HL and IY");
528       return TRUE;
529     }
530 }
531 
532 static PAIR_ID
getDeadPairId(const iCode * ic)533 getDeadPairId (const iCode *ic)
534 {
535   if (isPairDead (PAIR_BC, ic))
536     {
537       return PAIR_BC;
538     }
539   else if (!IS_GB && isPairDead (PAIR_DE, ic))
540     {
541       return PAIR_DE;
542     }
543   else
544     {
545       return PAIR_INVALID;
546     }
547 }
548 
549 static PAIR_ID
getFreePairId(const iCode * ic)550 getFreePairId (const iCode *ic)
551 {
552   if (!isPairInUse (PAIR_BC, ic))
553     {
554       return PAIR_BC;
555     }
556   else if (!IS_GB && !isPairInUse (PAIR_DE, ic))
557     {
558       return PAIR_DE;
559     }
560   else
561     {
562       return PAIR_INVALID;
563     }
564 }
565 
566 static void
_tidyUp(char * buf)567 _tidyUp (char *buf)
568 {
569   /* Clean up the line so that it is 'prettier' */
570   /* If it is a label - can't do anything */
571   if (!strchr (buf, ':'))
572     {
573       /* Change the first (and probably only) ' ' to a tab so
574          everything lines up.
575        */
576       while (*buf)
577         {
578           if (*buf == ' ')
579             {
580               *buf = '\t';
581               break;
582             }
583           buf++;
584         }
585     }
586 }
587 
588 static void
_vemit2(const char * szFormat,va_list ap)589 _vemit2 (const char *szFormat, va_list ap)
590 {
591   struct dbuf_s dbuf;
592   char *buffer, *p, *nextp;
593 
594   dbuf_init (&dbuf, INITIAL_INLINEASM);
595 
596   dbuf_tvprintf (&dbuf, szFormat, ap);
597 
598   buffer = p = dbuf_detach_c_str (&dbuf);
599 
600   _tidyUp (p);
601 
602   /* Decompose multiline macros */
603   while ((nextp = strchr (p, '\n')))
604     {
605       *nextp = '\0';
606       emit_raw (p);
607       p = nextp + 1;
608     }
609 
610   emit_raw (p);
611 
612   dbuf_free (buffer);
613 }
614 
615 static void
emitDebug(const char * szFormat,...)616 emitDebug (const char *szFormat, ...)
617 {
618   if (!DISABLE_DEBUG && !regalloc_dry_run && options.verboseAsm)
619     {
620       va_list ap;
621 
622       va_start (ap, szFormat);
623       _vemit2 (szFormat, ap);
624       va_end (ap);
625     }
626 }
627 
628 static void
emit2(const char * szFormat,...)629 emit2 (const char *szFormat, ...)
630 {
631   if (!regalloc_dry_run)
632     {
633       va_list ap;
634 
635       va_start (ap, szFormat);
636       _vemit2 (szFormat, ap);
637       va_end (ap);
638     }
639 }
640 
641 static PAIR_ID
getPartPairId(const asmop * aop,int offset)642 getPartPairId (const asmop *aop, int offset)
643 {
644   if (aop->size <= offset + 1 || offset < 0)
645     return PAIR_INVALID;
646 
647   if (aop->type != AOP_REG)
648     return PAIR_INVALID;
649 
650   wassert (aop->aopu.aop_reg[offset] && aop->aopu.aop_reg[offset + 1]);
651 
652   if ((aop->aopu.aop_reg[offset]->rIdx == C_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == B_IDX))
653     return PAIR_BC;
654   if ((aop->aopu.aop_reg[offset]->rIdx == E_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == D_IDX))
655     return PAIR_DE;
656   if ((aop->aopu.aop_reg[offset]->rIdx == L_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == H_IDX))
657     return PAIR_HL;
658   if ((aop->aopu.aop_reg[offset]->rIdx == IYL_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == IYH_IDX))
659     return PAIR_IY;
660 
661   return PAIR_INVALID;
662 }
663 
664 static PAIR_ID
getPairId_o(const asmop * aop,int offset)665 getPairId_o (const asmop *aop, int offset)
666 {
667   if (offset + 2 <= aop->size)
668     {
669       if (aop->type == AOP_REG)
670         {
671           wassert (aop->aopu.aop_reg[offset] && aop->aopu.aop_reg[offset + 1]);
672 
673           if ((aop->aopu.aop_reg[offset]->rIdx == C_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == B_IDX))
674             {
675               return PAIR_BC;
676             }
677           if ((aop->aopu.aop_reg[offset]->rIdx == E_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == D_IDX))
678             {
679               return PAIR_DE;
680             }
681           if ((aop->aopu.aop_reg[offset]->rIdx == L_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == H_IDX))
682             {
683               return PAIR_HL;
684             }
685           if ((aop->aopu.aop_reg[offset]->rIdx == IYL_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == IYH_IDX))
686             {
687               return PAIR_IY;
688             }
689         }
690       else if (aop->type == AOP_STR)
691         {
692           int i;
693           for (i = 0; i < NUM_PAIRS; i++)
694             {
695               if (!strcmp (aop->aopu.aop_str[offset], _pairs[i].l) && !strcmp (aop->aopu.aop_str[offset + 1], _pairs[i].h))
696                 return i;
697             }
698         }
699     }
700   return PAIR_INVALID;
701 }
702 
703 static PAIR_ID
getPairId(const asmop * aop)704 getPairId (const asmop *aop)
705 {
706   if (aop->size != 2)
707     return PAIR_INVALID;
708   return (getPairId_o (aop, 0));
709 }
710 
711 
712 /*-----------------------------------------------------------------*/
713 /* z80_emitDebuggerSymbol - associate the current code location    */
714 /*   with a debugger symbol                                        */
715 /*-----------------------------------------------------------------*/
716 void
z80_emitDebuggerSymbol(const char * debugSym)717 z80_emitDebuggerSymbol (const char *debugSym)
718 {
719   genLine.lineElement.isDebug = 1;
720   emit2 ("%s !equ .", debugSym);
721   emit2 ("!global", debugSym);
722   genLine.lineElement.isDebug = 0;
723 }
724 
725 // Todo: Handle IY correctly.
726 static unsigned char
ld_cost(const asmop * op1,const asmop * op2)727 ld_cost (const asmop *op1, const asmop *op2)
728 {
729   AOP_TYPE op1type = op1->type;
730   AOP_TYPE op2type = op2->type;
731 
732   /* Costs are symmetric */
733   if (op2type == AOP_REG || op2type == AOP_DUMMY)
734     {
735       const asmop *tmp = op1;
736       op1 = op2;
737       op2 = tmp;
738       op1type = op1->type;
739       op2type = op2->type;
740     }
741 
742   switch (op1type)
743     {
744     case AOP_REG:
745     case AOP_DUMMY:
746       switch (op2type)
747         {
748         case AOP_REG:
749         case AOP_DUMMY:
750           return (1);
751         case AOP_IMMD:
752         case AOP_LIT:
753           return (2);
754         case AOP_SFR:          /* 2 from in a, (...) */
755           return ((aopInReg (op1, 0, A_IDX) || op1type == AOP_DUMMY) ? 2 : 3);
756         case AOP_STK:
757           return (3);
758         case AOP_HL:           /* 3 from ld hl, #... */
759           return (4);
760         case AOP_IY:           /* 4 from ld iy, #... */
761         case AOP_EXSTK:        /* 4 from ld iy, #... */
762           return (7);
763         case AOP_PAIRPTR:
764           if (op2->aopu.aop_pairId == PAIR_HL)
765             return (1);
766           if (op2->aopu.aop_pairId == PAIR_IY || op2->aopu.aop_pairId == PAIR_IX)
767             return (3);
768           if (op2->aopu.aop_pairId == PAIR_BC || op2->aopu.aop_pairId == PAIR_DE)
769             return ((aopInReg (op1, 0, A_IDX) || op1type == AOP_DUMMY) ? 1 : 2);
770         default:
771           printf ("ld_cost op1: AOP_REG, op2: %d\n", (int) (op2type));
772           wassert (0);
773         }
774     case AOP_SFR:              /* 2 from out (...), a */
775       switch (op2type)
776         {
777         case AOP_REG:
778         case AOP_DUMMY:
779           return (2);
780         case AOP_IMMD:
781         case AOP_LIT:
782           return (4);
783         case AOP_STK:
784           return (5);
785         case AOP_HL:           /* 3 from ld hl, #... */
786           return (6);
787         case AOP_SFR:
788           return (4);
789         case AOP_IY:           /* 4 from ld iy, #... */
790         case AOP_EXSTK:        /* 4 from ld iy, #... */
791           return (9);
792         default:
793           printf ("ld_cost op1: AOP_SFR, op2: %d\n", (int) (op2type));
794           wassert (0);
795         }
796     case AOP_IY:               /* 4 from ld iy, #... */
797     case AOP_EXSTK:            /* 4 from ld iy, #... */
798       switch (op2type)
799         {
800         case AOP_IMMD:
801         case AOP_LIT:
802           return (8);
803         case AOP_SFR:          /* 2 from in a, (...) */
804           return (9);
805         case AOP_STK:
806         case AOP_HL:           /* 3 from ld hl, #... */
807           return (10);
808         case AOP_IY:
809         case AOP_EXSTK:
810           return (16);
811         default:
812           printf ("ld_cost op1: AOP_IY, op2: %d\n", (int) (op2type));
813           wassert (0);
814         }
815     case AOP_STK:
816       switch (op2type)
817         {
818         case AOP_IMMD:
819         case AOP_LIT:
820           return (4);
821         case AOP_SFR:          /* 2 from in a, (...) */
822           return (5);
823         case AOP_STK:
824           return (6);
825         case AOP_HL:
826           return (7);
827         case AOP_IY:           /* 4 from ld iy, #... */
828         case AOP_EXSTK:
829           return (10);
830         case AOP_PAIRPTR:
831           if (op2->aopu.aop_pairId == PAIR_HL || op2->aopu.aop_pairId == PAIR_BC || op2->aopu.aop_pairId == PAIR_DE)
832             return (4);
833           if (op2->aopu.aop_pairId == PAIR_IY || op2->aopu.aop_pairId == PAIR_IX)
834             return (6);
835         default:
836           printf ("ld_cost op1: AOP_STK, op2: %d\n", (int) (op2type));
837           wassert (0);
838         }
839     case AOP_HL:               /* 3 from ld hl, #... */
840       switch (op2type)
841         {
842         case AOP_REG:
843         case AOP_DUMMY:
844           return (4);
845         case AOP_IMMD:
846         case AOP_LIT:
847           return (5);
848         case AOP_STK:
849           return (7);
850         case AOP_SFR:
851         case AOP_HL:
852           return (6);
853         case AOP_IY:           /* 4 from ld iy, #... */
854         case AOP_EXSTK:
855           return (11);
856         default:
857           printf ("ld_cost op1: AOP_HL, op2: %d", (int) (op2type));
858           wassert (0);
859         }
860     case AOP_LIT:
861     case AOP_IMMD:
862       wassertl (0, "Trying to assign a value to a literal");
863       break;
864     default:
865       printf ("ld_cost op1: %d\n", (int) (op1type));
866       wassert (0);
867     }
868   return (8);                   // Fallback
869 }
870 
871 static unsigned char
op8_cost(const asmop * op2)872 op8_cost (const asmop * op2)
873 {
874   switch (op2->type)
875     {
876     case AOP_REG:
877     case AOP_DUMMY:
878       return (1);
879     case AOP_IMMD:
880     case AOP_LIT:
881       return (2);
882     case AOP_STK:
883       return (3);
884     case AOP_HL:
885       return (4);
886     case AOP_IY:               /* 4 from ld iy, #... */
887     case AOP_EXSTK:            /* 4 from ld iy, #... */
888       return (7);
889     case AOP_PAIRPTR:
890       if (op2->aopu.aop_pairId == PAIR_HL)
891         return (1);
892       if (op2->aopu.aop_pairId == PAIR_IY || op2->aopu.aop_pairId == PAIR_IX)
893         return (3);
894     default:
895       printf ("op8_cost op2: %d\n", (int) (op2->type));
896       wassert (0);
897     }
898   return (8);                   // Fallback
899 }
900 
901 static unsigned char
bit8_cost(const asmop * op1)902 bit8_cost (const asmop * op1)
903 {
904   switch (op1->type)
905     {
906     case AOP_REG:
907     case AOP_DUMMY:
908       return (2);
909     case AOP_STK:
910       return (4);
911     case AOP_HL:
912       return (5);
913     case AOP_IY:               /* 4 from ld iy, #... */
914     case AOP_EXSTK:            /* 4 from ld iy, #... */
915       return (8);
916     default:
917       printf ("bit8_cost op1: %d\n", (int) (op1->type));
918       wassert (0);
919     }
920   return (8);                   //Fallback
921 }
922 
923 static unsigned char
emit3Cost(enum asminst inst,const asmop * op1,int offset1,const asmop * op2,int offset2)924 emit3Cost (enum asminst inst, const asmop *op1, int offset1, const asmop *op2, int offset2)
925 {
926   if (op2 && offset2 >= op2->size)
927     op2 = ASMOP_ZERO;
928 
929   switch (inst)
930     {
931     case A_CPL:
932     case A_RLA:
933     case A_RLCA:
934     case A_RRA:
935     case A_RRCA:
936       return (1);
937     case A_NEG:
938       return(2);
939     case A_LD:
940       return (ld_cost (op1, op2));
941     case A_ADD:
942     case A_ADC:
943     case A_AND:
944     case A_CP:
945     case A_OR:
946     case A_SBC:
947     case A_SUB:
948     case A_XOR:
949       return (op8_cost (op2));
950     case A_DEC:
951     case A_INC:
952       return (op8_cost (op1));
953     case A_RL:
954     case A_RLC:
955     case A_RR:
956     case A_RRC:
957     case A_SLA:
958     case A_SRA:
959     case A_SRL:
960     case A_SWAP:
961       return (bit8_cost (op1));
962     default:
963       wassertl (0, "Tried get cost for unknown instruction");
964     }
965   return (0);
966 }
967 
968 static void
emit3_o(enum asminst inst,asmop * op1,int offset1,asmop * op2,int offset2)969 emit3_o (enum asminst inst, asmop *op1, int offset1, asmop *op2, int offset2)
970 {
971   unsigned char cost;
972 
973   regalloc_dry_run_cost += emit3Cost (inst, op1, offset1, op2, offset2);
974   if (regalloc_dry_run)
975     return;
976 
977   cost = regalloc_dry_run_cost;
978   if (!op1)
979     emit2 ("%s", asminstnames[inst]);
980   else if (!op2)
981     emit2 ("%s %s", asminstnames[inst], aopGet (op1, offset1, FALSE));
982   else
983     {
984       char *l = Safe_strdup (aopGet (op1, offset1, FALSE));
985       //emit2("%s %s, %s", asminstnames[inst], aopGet(op1, offset1, FALSE), aopGet(op2, offset2, FALSE));
986       emit2 ("%s %s, %s", asminstnames[inst], l, aopGet (op2, offset2, FALSE));
987       Safe_free (l);
988     }
989 
990   regalloc_dry_run_cost = cost;
991   //emitDebug(";emit3_o cost: %d total so far: %d", (int)emit3Cost(inst, op1, offset1, op2, offset2), (int)cost);
992 }
993 
994 static void
emit3(enum asminst inst,asmop * op1,asmop * op2)995 emit3 (enum asminst inst, asmop *op1, asmop *op2)
996 {
997   emit3_o (inst, op1, 0, op2, 0);
998 }
999 
1000 static void
_emitMove(const char * to,const char * from)1001 _emitMove (const char *to, const char *from)
1002 {
1003   if (STRCASECMP (to, from) != 0)
1004     {
1005       emit2 ("ld %s,%s", to, from);
1006     }
1007   else
1008     {
1009       // Optimise it out.
1010       // Could leave this to the peephole, but sometimes the peephole is inhibited.
1011     }
1012 }
1013 
1014 static void
_emitMove3(asmop * to,int to_offset,asmop * from,int from_offset)1015 _emitMove3 (asmop *to, int to_offset, asmop *from, int from_offset)
1016 {
1017   /* Todo: Longer list of moves that can be optimized out. */
1018   if (to_offset == from_offset)
1019     {
1020       if (to->type == AOP_REG && from->type == AOP_REG && to->aopu.aop_reg[to_offset] == from->aopu.aop_reg[from_offset])
1021         return;
1022     }
1023 
1024   emit3_o (A_LD, to, to_offset, from, from_offset);
1025 }
1026 
1027 #if 0
1028 static const char *aopNames[] =
1029 {
1030   "AOP_INVALID",
1031   "AOP_LIT",
1032   "AOP_REG",
1033   "AOP_DIR",
1034   "AOP_SFR",
1035   "AOP_STK",
1036   "AOP_IMMD",
1037   "AOP_STR",
1038   "AOP_CRY",
1039   "AOP_IY",
1040   "AOP_HL",
1041   "AOP_EXSTK",
1042   "AOP_PAIRPT",
1043   "AOP_DUMMY"
1044 };
1045 
1046 static void
1047 aopDump (const char *plabel, asmop * aop)
1048 {
1049   int i;
1050   char regbuf[9];
1051   char *rbp = regbuf;
1052 
1053   emitDebug ("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
1054   switch (aop->type)
1055     {
1056     case AOP_EXSTK:
1057     case AOP_STK:
1058       emitDebug (";  aop_stk %d", aop->aopu.aop_stk);
1059       break;
1060     case AOP_REG:
1061       for (i = aop->size - 1; i >= 0; i--)
1062         *rbp++ = *(aop->aopu.aop_reg[i]->name);
1063       *rbp = '\0';
1064       emitDebug (";  reg = %s", regbuf);
1065       break;
1066     case AOP_PAIRPTR:
1067       emitDebug (";  pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
1068 
1069     default:
1070       /* No information. */
1071       break;
1072     }
1073 }
1074 #endif
1075 
1076 static void
_moveA(const char * moveFrom)1077 _moveA (const char *moveFrom)
1078 {
1079   _emitMove ("a", moveFrom);
1080 }
1081 
1082 /* Load aop into A */
1083 static void
_moveA3(asmop * from,int offset)1084 _moveA3 (asmop * from, int offset)
1085 {
1086   _emitMove3 (ASMOP_A, 0, from, offset);
1087 }
1088 
1089 static const char *
getPairName(asmop * aop)1090 getPairName (asmop *aop)
1091 {
1092   if (aop->type == AOP_REG)
1093     {
1094       switch (aop->aopu.aop_reg[0]->rIdx)
1095         {
1096         case C_IDX:
1097           return "bc";
1098           break;
1099         case E_IDX:
1100           return "de";
1101           break;
1102         case L_IDX:
1103           return "hl";
1104           break;
1105         case IYL_IDX:
1106           return "iy";
1107           break;
1108         }
1109     }
1110   else if (aop->type == AOP_STR)
1111     {
1112       int i;
1113       for (i = 0; i < NUM_PAIRS; i++)
1114         {
1115           if (strcmp (aop->aopu.aop_str[0], _pairs[i].l) == 0)
1116             return _pairs[i].name;
1117         }
1118     }
1119   wassertl (0, "Tried to get the pair name of something that isn't a pair");
1120   return NULL;
1121 }
1122 
1123 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
1124 static bool
isPair(const asmop * aop)1125 isPair (const asmop *aop)
1126 {
1127   return (getPairId (aop) != PAIR_INVALID);
1128 }
1129 
1130 /** Returns TRUE if the registers used in aop cannot be split into high
1131     and low halves */
1132 static bool
isUnsplitable(const asmop * aop)1133 isUnsplitable (const asmop * aop)
1134 {
1135   switch (getPairId (aop))
1136     {
1137     case PAIR_IX:
1138     case PAIR_IY:
1139       return TRUE;
1140     default:
1141       return FALSE;
1142     }
1143   return FALSE;
1144 }
1145 
1146 static bool
isPtrPair(const asmop * aop)1147 isPtrPair (const asmop * aop)
1148 {
1149   PAIR_ID pairId = getPairId (aop);
1150   switch (pairId)
1151     {
1152     case PAIR_HL:
1153     case PAIR_IY:
1154     case PAIR_IX:
1155       return TRUE;
1156     default:
1157       return FALSE;
1158     }
1159 }
1160 
1161 static void
spillPair(PAIR_ID pairId)1162 spillPair (PAIR_ID pairId)
1163 {
1164   _G.pairs[pairId].last_type = AOP_INVALID;
1165   _G.pairs[pairId].base = NULL;
1166 }
1167 
1168 /* Given a register name, spill the pair (if any) the register is part of */
1169 static void
spillPairReg(const char * regname)1170 spillPairReg (const char *regname)
1171 {
1172   if (strlen (regname) == 1)
1173     {
1174       switch (*regname)
1175         {
1176         case 'h':
1177         case 'l':
1178           spillPair (PAIR_HL);
1179           break;
1180         case 'd':
1181         case 'e':
1182           spillPair (PAIR_DE);
1183           break;
1184         case 'b':
1185         case 'c':
1186           spillPair (PAIR_BC);
1187           break;
1188         }
1189     }
1190 }
1191 
1192 static void
_push(PAIR_ID pairId)1193 _push (PAIR_ID pairId)
1194 {
1195   emit2 ("push %s", _pairs[pairId].name);
1196   regalloc_dry_run_cost += (pairId == PAIR_IX || pairId == PAIR_IY ? 2 : 1);
1197   _G.stack.pushed += 2;
1198 }
1199 
1200 static void
_pop(PAIR_ID pairId)1201 _pop (PAIR_ID pairId)
1202 {
1203   if (pairId != PAIR_INVALID)
1204     {
1205       emit2 ("pop %s", _pairs[pairId].name);
1206       regalloc_dry_run_cost += (pairId == PAIR_IX || pairId == PAIR_IY ? 2 : 1);
1207       _G.stack.pushed -= 2;
1208       spillPair (pairId);
1209     }
1210 }
1211 
1212 static void
genMovePairPair(PAIR_ID srcPair,PAIR_ID dstPair)1213 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
1214 {
1215   switch (dstPair)
1216     {
1217     case PAIR_IX:
1218     case PAIR_IY:
1219     case PAIR_AF:
1220       _push (srcPair);
1221       _pop (dstPair);
1222       break;
1223     case PAIR_BC:
1224     case PAIR_DE:
1225     case PAIR_HL:
1226       if (srcPair == PAIR_IX || srcPair == PAIR_IY)
1227         {
1228           _push (srcPair);
1229           _pop (dstPair);
1230         }
1231       else
1232         {
1233           emit2 ("ld %s, %s", _pairs[dstPair].l, _pairs[srcPair].l);
1234           emit2 ("ld %s, %s", _pairs[dstPair].h, _pairs[srcPair].h);
1235           regalloc_dry_run_cost += 2;
1236         }
1237       break;
1238     default:
1239       wassertl (0, "Tried to move a nonphysical pair");
1240     }
1241   _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
1242   _G.pairs[dstPair].base = _G.pairs[srcPair].base;
1243   _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
1244 }
1245 
1246 
1247 /*-----------------------------------------------------------------*/
1248 /* newAsmop - creates a new asmOp                                  */
1249 /*-----------------------------------------------------------------*/
1250 static asmop *
newAsmop(short type)1251 newAsmop (short type)
1252 {
1253   asmop *aop;
1254 
1255   aop = traceAlloc (&_G.trace.aops, Safe_alloc (sizeof (asmop)));
1256   aop->type = type;
1257   memset (aop->regs, -1, 9);
1258   return aop;
1259 }
1260 
1261 /*-----------------------------------------------------------------*/
1262 /* aopForSym - for a true symbol                                   */
1263 /*-----------------------------------------------------------------*/
1264 static asmop *
aopForSym(const iCode * ic,symbol * sym,bool requires_a)1265 aopForSym (const iCode * ic, symbol * sym, bool requires_a)
1266 {
1267   asmop *aop;
1268   memmap *space;
1269 
1270   wassert (ic);
1271   wassert (sym);
1272   wassert (sym->etype);
1273 
1274   space = SPEC_OCLS (sym->etype);
1275 
1276   /* if already has one */
1277   if (sym->aop)
1278     {
1279       return sym->aop;
1280     }
1281 
1282   /* Assign depending on the storage class */
1283   if (sym->onStack || sym->iaccess)
1284     {
1285       /* The pointer that is used depends on how big the offset is.
1286          Normally everything is AOP_STK, but for offsets of < -128 or
1287          > 127 on the Z80 an extended stack pointer is used.
1288        */
1289       if (!IS_GB && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int) (INT8MAX - getSize (sym->type))))
1290         {
1291           emitDebug ("; AOP_EXSTK for %s, _G.omitFramePtr %d, sym->stack %d, size %d", sym->rname, (int) (_G.omitFramePtr),
1292                      sym->stack, getSize (sym->type));
1293           sym->aop = aop = newAsmop (AOP_EXSTK);
1294         }
1295       else
1296         {
1297           emitDebug ("; AOP_STK for %s", sym->rname);
1298           sym->aop = aop = newAsmop (AOP_STK);
1299         }
1300 
1301       aop->size = getSize (sym->type);
1302       aop->aopu.aop_stk = sym->stack;
1303       return aop;
1304     }
1305 
1306   /* special case for a function */
1307   if (IS_FUNC (sym->type))
1308     {
1309       sym->aop = aop = newAsmop (AOP_IMMD);
1310       aop->aopu.aop_immd = traceAlloc (&_G.trace.aops, Safe_strdup (sym->rname));
1311       aop->size = 2;
1312       return aop;
1313     }
1314 
1315   if (IN_REGSP (space))
1316     {
1317       /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
1318       if (IS_GB)
1319         {
1320           /* if it is in direct space */
1321           if (!requires_a)
1322             {
1323               sym->aop = aop = newAsmop (AOP_SFR);
1324               aop->aopu.aop_dir = sym->rname;
1325               aop->size = getSize (sym->type);
1326               /* emitDebug ("; AOP_SFR for %s", sym->rname); */
1327               return aop;
1328             }
1329         }
1330       else
1331         {
1332           /*.p.t.20030716 adding SFR support to the Z80 port */
1333           aop = newAsmop (AOP_SFR);
1334           sym->aop = aop;
1335           aop->aopu.aop_dir = sym->rname;
1336           aop->size = getSize (sym->type);
1337           aop->paged = FUNC_REGBANK (sym->type);
1338           aop->bcInUse = isPairInUse (PAIR_BC, ic);
1339           /* emitDebug (";Z80 AOP_SFR for %s banked:%d bc:%d", sym->rname, FUNC_REGBANK (sym->type), aop->bcInUse); */
1340 
1341           return (aop);
1342         }
1343     }
1344 
1345   /* only remaining is far space */
1346   /* in which case DPTR gets the address */
1347   if (IS_GB || IY_RESERVED)
1348     {
1349       /* emitDebug ("; AOP_HL for %s", sym->rname); */
1350       sym->aop = aop = newAsmop (AOP_HL);
1351     }
1352   else
1353     sym->aop = aop = newAsmop (AOP_IY);
1354 
1355   aop->size = getSize (sym->type);
1356   aop->aopu.aop_dir = sym->rname;
1357 
1358   /* if it is in code space */
1359   if (IN_CODESPACE (space))
1360     aop->code = 1;
1361 
1362   return aop;
1363 }
1364 
1365 /*-----------------------------------------------------------------*/
1366 /* aopForRemat - rematerializes an object                          */
1367 /*-----------------------------------------------------------------*/
1368 static asmop *
aopForRemat(symbol * sym)1369 aopForRemat (symbol *sym)
1370 {
1371   iCode *ic = sym->rematiCode;
1372   asmop *aop = newAsmop (AOP_IMMD);
1373   int val = 0;
1374   struct dbuf_s dbuf;
1375 
1376   wassert(ic);
1377 
1378   for (;;)
1379     {
1380       if (ic->op == '+')
1381         {
1382           if (isOperandLiteral (IC_RIGHT (ic)))
1383             {
1384               val += (int) operandLitValue (IC_RIGHT (ic));
1385               ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
1386             }
1387           else
1388             {
1389               val += (int) operandLitValue (IC_LEFT (ic));
1390               ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
1391             }
1392         }
1393       else if (ic->op == '-')
1394         {
1395           val -= (int) operandLitValue (IC_RIGHT (ic));
1396           ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
1397         }
1398       else if (IS_CAST_ICODE (ic))
1399         {
1400           ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
1401         }
1402       else if (ic->op == ADDRESS_OF)
1403         {
1404           val += (int) operandLitValue (IC_RIGHT (ic));
1405           break;
1406         }
1407       else
1408         break;
1409     }
1410 
1411   dbuf_init (&dbuf, 128);
1412   if (val)
1413     {
1414       dbuf_printf (&dbuf, "(%s %c 0x%04x)", OP_SYMBOL (IC_LEFT (ic))->rname, val >= 0 ? '+' : '-', abs (val) & 0xffff);
1415     }
1416   else
1417     {
1418       dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname);
1419     }
1420 
1421   aop->aopu.aop_immd = traceAlloc (&_G.trace.aops, dbuf_detach_c_str (&dbuf));
1422   return aop;
1423 }
1424 
1425 /*-----------------------------------------------------------------*/
1426 /* regsInCommon - two operands have some registers in common       */
1427 /*-----------------------------------------------------------------*/
1428 static bool
regsInCommon(operand * op1,operand * op2)1429 regsInCommon (operand * op1, operand * op2)
1430 {
1431   symbol *sym1, *sym2;
1432   int i;
1433 
1434   /* if they have registers in common */
1435   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1436     return FALSE;
1437 
1438   sym1 = OP_SYMBOL (op1);
1439   sym2 = OP_SYMBOL (op2);
1440 
1441   if (sym1->nRegs == 0 || sym2->nRegs == 0)
1442     return FALSE;
1443 
1444   for (i = 0; i < sym1->nRegs; i++)
1445     {
1446       int j;
1447       if (!sym1->regs[i])
1448         continue;
1449 
1450       for (j = 0; j < sym2->nRegs; j++)
1451         {
1452           if (!sym2->regs[j])
1453             continue;
1454 
1455           if (sym2->regs[j] == sym1->regs[i])
1456             return TRUE;
1457         }
1458     }
1459 
1460   return FALSE;
1461 }
1462 
1463 /*-----------------------------------------------------------------*/
1464 /* operandsEqu - equivalent                                        */
1465 /*-----------------------------------------------------------------*/
1466 static bool
operandsEqu(operand * op1,operand * op2)1467 operandsEqu (operand * op1, operand * op2)
1468 {
1469   symbol *sym1, *sym2;
1470 
1471   /* if they not symbols */
1472   if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1473     return FALSE;
1474 
1475   sym1 = OP_SYMBOL (op1);
1476   sym2 = OP_SYMBOL (op2);
1477 
1478   /* if both are itemps & one is spilt
1479      and the other is not then false */
1480   if (IS_ITEMP (op1) && IS_ITEMP (op2) && sym1->isspilt != sym2->isspilt)
1481     return FALSE;
1482 
1483   /* if they are the same */
1484   if (sym1 == sym2)
1485     return 1;
1486 
1487   if (sym1->rname[0] && sym2->rname[0] && strcmp (sym1->rname, sym2->rname) == 0)
1488     return 2;
1489 
1490   /* if left is a tmp & right is not */
1491   if (IS_ITEMP (op1) && !IS_ITEMP (op2) && sym1->isspilt && (sym1->usl.spillLoc == sym2))
1492     return 3;
1493 
1494   if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (sym2->usl.spillLoc == sym1))
1495     return 4;
1496 
1497   return FALSE;
1498 }
1499 
1500 /*-----------------------------------------------------------------*/
1501 /* sameRegs - two asmops have the same registers                   */
1502 /*-----------------------------------------------------------------*/
1503 static bool
sameRegs(asmop * aop1,asmop * aop2)1504 sameRegs (asmop * aop1, asmop * aop2)
1505 {
1506   int i;
1507 
1508   if (aop1->type == AOP_SFR || aop2->type == AOP_SFR)
1509     return FALSE;
1510 
1511   if (aop1 == aop2)
1512     return TRUE;
1513 
1514   if (! regalloc_dry_run && // Todo: Check if always enabling this even for dry runs tends to result in better code.
1515     (aop1->type == AOP_STK && aop2->type == AOP_STK ||
1516     aop1->type == AOP_EXSTK && aop2->type == AOP_EXSTK))
1517     return (aop1->aopu.aop_stk == aop2->aopu.aop_stk);
1518 
1519   if (aop1->type != AOP_REG || aop2->type != AOP_REG)
1520     return FALSE;
1521 
1522   if (aop1->size != aop2->size)
1523     return FALSE;
1524 
1525   for (i = 0; i < aop1->size; i++)
1526     if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1527       return FALSE;
1528 
1529   return TRUE;
1530 }
1531 
1532 /*-----------------------------------------------------------------*/
1533 /* aopOp - allocates an asmop for an operand  :                    */
1534 /*-----------------------------------------------------------------*/
1535 static void
aopOp(operand * op,const iCode * ic,bool result,bool requires_a)1536 aopOp (operand *op, const iCode *ic, bool result, bool requires_a)
1537 {
1538   asmop *aop;
1539   symbol *sym;
1540   int i;
1541 
1542   if (!op)
1543     return;
1544 
1545   /* if this a literal */
1546   if (IS_OP_LITERAL (op)) /* TODO:  && !op->isaddr, handle address literals in a sane way */
1547     {
1548       op->aop = aop = newAsmop (AOP_LIT);
1549       aop->aopu.aop_lit = OP_VALUE (op);
1550       aop->size = getSize (operandType (op));
1551       return;
1552     }
1553 
1554   /* if already has a asmop then continue */
1555   if (op->aop)
1556     {
1557       if (op->aop->type == AOP_SFR)
1558         {
1559           op->aop->bcInUse = isPairInUse (PAIR_BC, ic);
1560         }
1561       return;
1562     }
1563 
1564   /* if the underlying symbol has a aop */
1565   if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
1566     {
1567       op->aop = OP_SYMBOL (op)->aop;
1568       if (op->aop->type == AOP_SFR)
1569         {
1570           op->aop->bcInUse = isPairInUse (PAIR_BC, ic);
1571         }
1572       return;
1573     }
1574 
1575   /* if this is a true symbol */
1576   if (IS_TRUE_SYMOP (op))
1577     {
1578       op->aop = aopForSym (ic, OP_SYMBOL (op), requires_a);
1579       return;
1580     }
1581 
1582   /* this is a temporary : this has
1583      only four choices :
1584      a) register
1585      b) spillocation
1586      c) rematerialize
1587      d) conditional
1588      e) can be a return use only */
1589 
1590   sym = OP_SYMBOL (op);
1591 
1592   /* if the type is a conditional */
1593   if (sym->regType == REG_CND)
1594     {
1595       aop = op->aop = sym->aop = newAsmop (AOP_CRY);
1596       aop->size = 0;
1597       return;
1598     }
1599 
1600   /* if it is spilt then two situations
1601      a) is rematerialize
1602      b) has a spill location */
1603   if (sym->isspilt || sym->nRegs == 0)
1604     {
1605       if (sym->ruonly)
1606         {
1607           int i;
1608           aop = op->aop = sym->aop = newAsmop (AOP_STR);
1609           aop->size = getSize (sym->type);
1610           for (i = 0; i < 4; i++)
1611             aop->aopu.aop_str[i] = ASMOP_RETURN->aopu.aop_reg[i]->name;
1612           return;
1613         }
1614 
1615       if (sym->accuse)
1616         {
1617           if (sym->accuse == ACCUSE_A) /* For compability with old register allocator only */
1618             {
1619               sym->aop = op->aop = aop = newAsmop (AOP_REG);
1620               aop->size = getSize (sym->type);
1621               wassertl (aop->size == 1, "Internal error: Caching in A, but too big to fit in A");
1622               aop->aopu.aop_reg[0] = regsZ80 + A_IDX;
1623             }
1624           else if (sym->accuse == ACCUSE_IY) /* For compability with old register allocator only */
1625             {
1626               sym->aop = op->aop = aop = newAsmop (AOP_REG);
1627               aop->size = getSize (sym->type);
1628               wassertl (aop->size <= 2, "Internal error: Caching in IY, but too big to fit in IY");
1629               aop->aopu.aop_reg[0] = regsZ80 + IYL_IDX;
1630               aop->aopu.aop_reg[0] = regsZ80 + IYH_IDX;
1631             }
1632           else
1633             {
1634               wassertl (0, "Marked as being allocated into A or IY but is actually in neither");
1635             }
1636           return;
1637         }
1638 
1639       /* rematerialize it NOW */
1640       if (sym->remat)
1641         {
1642           sym->aop = op->aop = aop = aopForRemat (sym);
1643           aop->size = getSize (sym->type);
1644           return;
1645         }
1646 
1647       /* On-stack for dry run. */
1648       if (sym->nRegs && regalloc_dry_run)
1649         {
1650           sym->aop = op->aop = aop = newAsmop (AOP_STK);
1651           aop->size = getSize (sym->type);
1652           return;
1653         }
1654 
1655       /* On stack. */
1656       if (sym->isspilt && sym->usl.spillLoc)
1657         {
1658           asmop *oldAsmOp = NULL;
1659 
1660           if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
1661             {
1662               /* force a new aop if sizes differ */
1663               oldAsmOp = sym->usl.spillLoc->aop;
1664               sym->usl.spillLoc->aop = NULL;
1665             }
1666           sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, requires_a);
1667           if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
1668             {
1669               /* Don't reuse the new aop, go with the last one */
1670               sym->usl.spillLoc->aop = oldAsmOp;
1671             }
1672           aop->size = getSize (sym->type);
1673           return;
1674         }
1675 
1676       /* else must be a dummy iTemp */
1677       sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
1678       aop->size = getSize (sym->type);
1679       return;
1680     }
1681 
1682   /* must be in a register */
1683   sym->aop = op->aop = aop = newAsmop (AOP_REG);
1684   aop->size = sym->nRegs;
1685   for (i = 0; i < sym->nRegs; i++)
1686     {
1687       wassertl (sym->regs[i], "Symbol in register, but no register assigned.");
1688       if(!sym->regs[i])
1689         fprintf(stderr, "Symbol %s at ic %d.\n", sym->name, ic->key);
1690       aop->aopu.aop_reg[i] = sym->regs[i];
1691       aop->regs[sym->regs[i]->rIdx] = i;
1692     }
1693 }
1694 
1695 /*-----------------------------------------------------------------*/
1696 /* freeAsmop - free up the asmop given to an operand               */
1697 /*----------------------------------------------------------------*/
1698 static void
freeAsmop(operand * op,asmop * aaop)1699 freeAsmop (operand * op, asmop *aaop)
1700 {
1701   asmop *aop;
1702 
1703   if (!op)
1704     aop = aaop;
1705   else
1706     aop = op->aop;
1707 
1708   if (!aop)
1709     return;
1710 
1711   if (aop->freed)
1712     goto dealloc;
1713 
1714   aop->freed = 1;
1715 
1716   if (aop->type == AOP_PAIRPTR && !IS_GB && aop->aopu.aop_pairId == PAIR_DE)
1717     {
1718       _pop (aop->aopu.aop_pairId);
1719     }
1720 
1721   if (getPairId (aop) == PAIR_HL)
1722     {
1723       spillPair (PAIR_HL);
1724     }
1725 
1726 dealloc:
1727   /* all other cases just dealloc */
1728   if (op)
1729     {
1730       op->aop = NULL;
1731       if (IS_SYMOP (op))
1732         {
1733           OP_SYMBOL (op)->aop = NULL;
1734           /* if the symbol has a spill */
1735           if (SPIL_LOC (op))
1736             SPIL_LOC (op)->aop = NULL;
1737         }
1738     }
1739 
1740 }
1741 
1742 static bool
isLitWord(const asmop * aop)1743 isLitWord (const asmop *aop)
1744 {
1745   /*    if (aop->size != 2)
1746      return FALSE; */
1747   switch (aop->type)
1748     {
1749     case AOP_IMMD:
1750     case AOP_LIT:
1751       return TRUE;
1752     default:
1753       return FALSE;
1754     }
1755 }
1756 
1757 static const char *
aopGetLitWordLong(const asmop * aop,int offset,bool with_hash)1758 aopGetLitWordLong (const asmop *aop, int offset, bool with_hash)
1759 {
1760   static struct dbuf_s dbuf = { 0 };
1761 
1762   if (dbuf_is_initialized (&dbuf))
1763     {
1764       dbuf_set_length (&dbuf, 0);
1765     }
1766   else
1767     {
1768       dbuf_init (&dbuf, 128);
1769     }
1770 
1771   /* depending on type */
1772   switch (aop->type)
1773     {
1774     case AOP_HL:
1775     case AOP_IY:
1776     case AOP_IMMD:
1777       /* PENDING: for re-target */
1778       if (with_hash)
1779         {
1780           dbuf_tprintf (&dbuf, "!hashedstr + %d", aop->aopu.aop_immd, offset);
1781         }
1782       else if (offset == 0)
1783         {
1784           dbuf_tprintf (&dbuf, "%s", aop->aopu.aop_immd);
1785         }
1786       else
1787         {
1788           dbuf_tprintf (&dbuf, "%s + %d", aop->aopu.aop_immd, offset);
1789         }
1790       break;
1791 
1792     case AOP_LIT:
1793     {
1794       value *val = aop->aopu.aop_lit;
1795       /* if it is a float then it gets tricky */
1796       /* otherwise it is fairly simple */
1797       if (!IS_FLOAT (val->type))
1798         {
1799           unsigned long long v = ullFromVal (val);
1800 
1801           v >>= (offset * 8);
1802 
1803           dbuf_tprintf (&dbuf, with_hash ? "!immedword" : "!constword", (unsigned long) (v & 0xffffull));
1804         }
1805       else
1806         {
1807           union
1808           {
1809             float f;
1810             unsigned char c[4];
1811           }
1812           fl;
1813           unsigned int i;
1814 
1815           /* it is type float */
1816           fl.f = (float) floatFromVal (val);
1817 
1818 #ifdef WORDS_BIGENDIAN
1819           i = fl.c[3 - offset] | (fl.c[3 - offset - 1] << 8);
1820 #else
1821           i = fl.c[offset] | (fl.c[offset + 1] << 8);
1822 #endif
1823           dbuf_tprintf (&dbuf, with_hash ? "!immedword" : "!constword", i);
1824         }
1825     }
1826     break;
1827 
1828     case AOP_REG:
1829     case AOP_STK:
1830     case AOP_DIR:
1831     case AOP_SFR:
1832     case AOP_STR:
1833     case AOP_CRY:
1834     case AOP_EXSTK:
1835     case AOP_PAIRPTR:
1836     case AOP_DUMMY:
1837       break;
1838 
1839     default:
1840       dbuf_destroy (&dbuf);
1841       fprintf (stderr, "aop->type: %d\n", aop->type);
1842       wassertl (0, "aopGetLitWordLong got unsupported aop->type");
1843       exit (0);
1844     }
1845   return dbuf_c_str (&dbuf);
1846 }
1847 
1848 static bool
isPtr(const char * s)1849 isPtr (const char *s)
1850 {
1851   if (!strcmp (s, "hl"))
1852     return TRUE;
1853   if (!strcmp (s, "ix"))
1854     return TRUE;
1855   if (!strcmp (s, "iy"))
1856     return TRUE;
1857   return FALSE;
1858 }
1859 
1860 static void
adjustPair(const char * pair,int * pold,int new_val)1861 adjustPair (const char *pair, int *pold, int new_val)
1862 {
1863   wassert (pair);
1864 
1865   while (*pold < new_val)
1866     {
1867       emit2 ("inc %s", pair);
1868       (*pold)++;
1869     }
1870   while (*pold > new_val)
1871     {
1872       emit2 ("dec %s", pair);
1873       (*pold)--;
1874     }
1875 }
1876 
1877 static void
spillCached(void)1878 spillCached (void)
1879 {
1880   spillPair (PAIR_HL);
1881   spillPair (PAIR_IY);
1882 }
1883 
1884 static bool
requiresHL(const asmop * aop)1885 requiresHL (const asmop * aop)
1886 {
1887   switch (aop->type)
1888     {
1889     case AOP_IY:
1890       return FALSE;
1891     case AOP_HL:
1892     case AOP_EXSTK:
1893       return TRUE;
1894     case AOP_STK:
1895       return (IS_GB || _G.omitFramePtr);
1896     case AOP_REG:
1897     {
1898       int i;
1899       for (i = 0; i < aop->size; i++)
1900         {
1901           wassert (aop->aopu.aop_reg[i]);
1902           if (aop->aopu.aop_reg[i]->rIdx == L_IDX || aop->aopu.aop_reg[i]->rIdx == H_IDX)
1903             return TRUE;
1904         }
1905     }
1906     case AOP_PAIRPTR:
1907       return (aop->aopu.aop_pairId == PAIR_HL);
1908     default:
1909       return FALSE;
1910     }
1911 }
1912 
1913 /*----------------------------------------------------------*/
1914 /* strtoul_z80: a wrapper to strtoul, which can also handle */
1915 /* hex numbers with a $ prefix.                             */
1916 /*----------------------------------------------------------*/
1917 static unsigned long int
strtoul_z80asm(const char * nptr,char ** endptr,int base)1918 strtoul_z80asm (const char *nptr, char **endptr, int base)
1919 {
1920   char *p = NULL;
1921   int i, flag = 0, len;
1922   unsigned long ret;
1923 
1924   if (nptr != NULL && (p = malloc ((len = strlen (nptr)) + 1 + 1)) != NULL)
1925     {
1926       memset (p, 0, len + 2);
1927       for (i = 0; i < len; i++)
1928         {
1929           if (!flag)
1930             if (isspace (nptr[i]))
1931               p[i] = nptr[i];
1932             else if (nptr[i] == '$')
1933               {
1934                 p[i] = '0';
1935                 p[i + 1] = 'x';
1936                 flag = 1;
1937               }
1938             else
1939               break;
1940           else
1941             p[i + 1] = nptr[i];
1942         }
1943     }
1944 
1945   if (flag)
1946     ret = strtoul (p, endptr, base);
1947   else
1948     ret = strtoul (nptr, endptr, base);
1949 
1950   if (p)
1951     free (p);
1952   return ret;
1953 }
1954 
1955 static void
fetchLitPair(PAIR_ID pairId,asmop * left,int offset)1956 fetchLitPair (PAIR_ID pairId, asmop *left, int offset)
1957 {
1958   const char *pair = _pairs[pairId].name;
1959   char *l = Safe_strdup (aopGetLitWordLong (left, offset, FALSE));
1960   char *base_str = Safe_strdup (aopGetLitWordLong (left, 0, FALSE));
1961   const char *base = base_str;
1962 
1963   wassert (pair);
1964 
1965   emitDebug (";fetchLitPair");
1966 
1967   if (isPtr (pair))
1968     {
1969       if (pairId == PAIR_HL || pairId == PAIR_IY)
1970         {
1971           if (pairId == PAIR_HL && base[0] == '0')      // Ugly workaround
1972             {
1973               unsigned int tmpoffset;
1974               const char *tmpbase;
1975               if (sscanf (base, "%xd", &tmpoffset) && (tmpbase = strchr (base, '+')))
1976                 {
1977                   offset = tmpoffset;
1978                   base = tmpbase++;
1979                 }
1980             }
1981           if ((_G.pairs[pairId].last_type == AOP_IMMD && left->type == AOP_IMMD) ||
1982               (_G.pairs[pairId].last_type == AOP_IY && left->type == AOP_IY) ||
1983               (_G.pairs[pairId].last_type == AOP_HL && left->type == AOP_HL))
1984             {
1985               if (!regalloc_dry_run && _G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base))  // Todo: Exact cost.
1986                 {
1987                   if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
1988                     {
1989                       adjustPair (pair, &_G.pairs[pairId].offset, offset);
1990                       goto adjusted;
1991                     }
1992                   if (pairId == PAIR_IY && offset == _G.pairs[pairId].offset)
1993                     goto adjusted;
1994                 }
1995             }
1996         }
1997 
1998       if (pairId == PAIR_HL && left->type == AOP_LIT && _G.pairs[pairId].last_type == AOP_LIT &&
1999           !IS_FLOAT (left->aopu.aop_lit->type) && offset == 0 && _G.pairs[pairId].offset == 0)
2000         {
2001           unsigned new_low, new_high, old_low, old_high;
2002           unsigned long v_new = ulFromVal (left->aopu.aop_lit);
2003           unsigned long v_old = strtoul_z80asm (_G.pairs[pairId].base, NULL, 0);
2004           new_low = (v_new >> 0) & 0xff;
2005           new_high = (v_new >> 8) & 0xff;
2006           old_low = (v_old >> 0) & 0xff;
2007           old_high = (v_old >> 8) & 0xff;
2008 
2009           /* Change lower byte only. */
2010           if (new_high == old_high)
2011             {
2012               emit3_o (A_LD, ASMOP_L, 0, left, 0);
2013               goto adjusted;
2014             }
2015           /* Change upper byte only. */
2016           else if (new_low == old_low)
2017             {
2018               emit3_o (A_LD, ASMOP_H, 0, left, 1);
2019               goto adjusted;
2020             }
2021         }
2022 
2023 
2024       _G.pairs[pairId].last_type = left->type;
2025       _G.pairs[pairId].base = traceAlloc (&_G.trace.aops, Safe_strdup (base));
2026       _G.pairs[pairId].offset = offset;
2027     }
2028   /* Both a lit on the right and a true symbol on the left */
2029   emit2 ("ld %s, !hashedstr", pair, l);
2030   regalloc_dry_run_cost += (pairId == PAIR_IX || pairId == PAIR_IY) ? 4 : 3;
2031   Safe_free (base_str);
2032   Safe_free (l);
2033   return;
2034 
2035 adjusted:
2036   _G.pairs[pairId].last_type = left->type;
2037   _G.pairs[pairId].base = traceAlloc (&_G.trace.aops, Safe_strdup (base));
2038   _G.pairs[pairId].offset = offset;
2039   Safe_free (base_str);
2040   Safe_free (l);
2041 }
2042 
2043 static PAIR_ID
makeFreePairId(const iCode * ic,bool * pisUsed)2044 makeFreePairId (const iCode * ic, bool * pisUsed)
2045 {
2046   *pisUsed = FALSE;
2047 
2048   if (ic != NULL)
2049     {
2050       if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue (ic->rMask, C_IDX))
2051         {
2052           return PAIR_BC;
2053         }
2054       else if (!IS_GB && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue (ic->rMask, E_IDX))
2055         {
2056           return PAIR_DE;
2057         }
2058       else
2059         {
2060           *pisUsed = TRUE;
2061           return PAIR_HL;
2062         }
2063     }
2064   else
2065     {
2066       *pisUsed = TRUE;
2067       return PAIR_HL;
2068     }
2069 }
2070 
2071 /* If ic != 0, we can safely use isPairDead(). */
2072 static void
fetchPairLong(PAIR_ID pairId,asmop * aop,const iCode * ic,int offset)2073 fetchPairLong (PAIR_ID pairId, asmop *aop, const iCode *ic, int offset)
2074 {
2075   emitDebug (";fetchPairLong");
2076 
2077   /* if this is rematerializable */
2078   if (isLitWord (aop))
2079     fetchLitPair (pairId, aop, offset);
2080   else
2081     {
2082       if (getPairId (aop) == pairId)
2083         {
2084           /* Do nothing */
2085         }
2086       else if (IS_EZ80_Z80 && aop->size - offset >= 2 && aop->type == AOP_STK)
2087         {
2088           int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2089           emit2 ("ld %s, %d (ix)", _pairs[pairId].name, fp_offset);
2090           regalloc_dry_run_cost += 3;
2091         }
2092       /* Getting the parameter by a pop / push sequence is cheaper when we have a free pair (except for the Rabbit, which has an even cheaper sp-relative load).
2093          Stack allocation can change after register allocation, so assume this optimization is not possible for the allocator's cost function (unless the stack location is for a parameter). */
2094       else if (!IS_RAB && aop->size - offset >= 2 &&
2095                (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (!regalloc_dry_run || aop->aopu.aop_stk > 0)
2096                && (aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) +
2097                    _G.stack.pushed) == 2 && ic && getFreePairId (ic) != PAIR_INVALID && getFreePairId (ic) != pairId)
2098         {
2099           PAIR_ID extrapair = getFreePairId (ic);
2100           _pop (extrapair);
2101           _pop (pairId);
2102           _push (pairId);
2103           _push (extrapair);
2104         }
2105       /* Todo: Use even cheaper ex hl, (sp) and ex iy, (sp) when possible. */
2106       else if ((!IS_RAB || pairId == PAIR_BC || pairId == PAIR_DE) && aop->size - offset >= 2 &&
2107                (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (!regalloc_dry_run || aop->aopu.aop_stk > 0)
2108                && (aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) +
2109                    _G.stack.pushed) == 0)
2110         {
2111           _pop (pairId);
2112           _push (pairId);
2113         }
2114       else if (!IS_GB && (aop->type == AOP_IY || aop->type == AOP_HL) && !(pairId == PAIR_IY && aop->size < 2))
2115         {
2116           /* Instead of fetching relative to IY, just grab directly
2117              from the address IY refers to */
2118           emit2 ("ld %s, (%s)", _pairs[pairId].name, aopGetLitWordLong (aop, offset, FALSE));
2119           regalloc_dry_run_cost += (pairId == PAIR_HL ? 3 : 4);
2120 
2121           if (aop->size < 2)
2122             {
2123               emit2 ("ld %s, !zero", _pairs[pairId].h);
2124               regalloc_dry_run_cost += 2;
2125             }
2126         }
2127       /* we need to get it byte by byte */
2128       else if (pairId == PAIR_HL && (IS_GB || (IY_RESERVED && (aop->type == AOP_HL || aop->type == AOP_EXSTK))) && requiresHL (aop))
2129         {
2130           if (!regalloc_dry_run)        // TODO: Fix this to get correct cost!
2131             aopGet (aop, offset, FALSE);
2132           switch (aop->size - offset)
2133             {
2134             case 1:
2135               emit2 ("ld l, !*hl");
2136               emit2 ("ld h, !immedbyte", 0);
2137               regalloc_dry_run_cost += 3;
2138               break;
2139             default:
2140               wassertl (aop->size - offset > 1, "Attempted to fetch no data into HL");
2141               if (IS_RAB || IS_TLCS90)
2142                 {
2143                   emit2 ("ld hl, 0 (hl)");
2144                   regalloc_dry_run_cost += 3;
2145                 }
2146               else if (IS_EZ80_Z80)
2147                 {
2148                   emit2 ("ld hl, (hl)");
2149                   regalloc_dry_run_cost += 2;
2150                 }
2151               else
2152                 {
2153                   if (ic && bitVectBitValue (ic->rMask, A_IDX))
2154                     _push (PAIR_AF);
2155 
2156                   emit2 ("ld a, !*hl");
2157                   emit2 ("inc hl");
2158                   emit2 ("ld h, !*hl");
2159                   emit2 ("ld l, a");
2160                   regalloc_dry_run_cost += 4;
2161 
2162                   if (ic && bitVectBitValue (ic->rMask, A_IDX))
2163                     _pop (PAIR_AF);
2164                 }
2165               break;
2166             }
2167         }
2168       else if (pairId == PAIR_IY)
2169         {
2170           /* The Rabbit has the ld iy, n (sp) instruction. */
2171           int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2172           int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
2173           if ((IS_RAB || IS_TLCS90) && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && abs (sp_offset) <= 127)
2174             {
2175               emit2 ("ld iy, %d (sp)", sp_offset);
2176               regalloc_dry_run_cost += 3;
2177             }
2178           else if (isPair (aop) && (IS_RAB || IS_TLCS90) && getPairId (aop) == PAIR_HL)
2179             {
2180               emit2 ("ld iy, hl");
2181               regalloc_dry_run_cost += (1 + IS_RAB);
2182             }
2183           else if (isPair (aop))
2184             {
2185               emit2 ("push %s", _pairs[getPairId (aop)].name);
2186               emit2 ("pop iy");
2187               regalloc_dry_run_cost += 3;
2188             }
2189           else
2190             {
2191               bool isUsed;
2192               PAIR_ID id = makeFreePairId (ic, &isUsed);
2193               if (isUsed)
2194                 _push (id);
2195               /* Can't load into parts, so load into HL then exchange. */
2196               if (!regalloc_dry_run)
2197                 {
2198                   emit2 ("ld %s, %s", _pairs[id].l, aopGet (aop, offset, FALSE));
2199                   emit2 ("ld %s, %s", _pairs[id].h, aopGet (aop, offset + 1, FALSE));
2200                 }
2201               regalloc_dry_run_cost += ld_cost (ASMOP_L, aop) + ld_cost (ASMOP_H, aop);
2202 
2203               if ((IS_RAB || IS_TLCS90) && id == PAIR_HL)
2204                 {
2205                   emit2 ("ld iy, hl");
2206                   regalloc_dry_run_cost += (1 + IS_RAB);
2207                 }
2208               else
2209                 {
2210                   emit2 ("push %s", _pairs[id].name);
2211                   emit2 ("pop iy");
2212                   regalloc_dry_run_cost += 3;
2213                 }
2214               if (isUsed)
2215                 _pop (id);
2216             }
2217         }
2218       else if (isUnsplitable (aop))
2219         {
2220           emit2 ("push %s", _pairs[getPairId (aop)].name);
2221           emit2 ("pop %s", _pairs[pairId].name);
2222           regalloc_dry_run_cost += (pairId == PAIR_IY ? 2 : 1) + (getPairId (aop) == PAIR_IY ? 2 : 1);
2223         }
2224       else
2225         {
2226           /* The Rabbit has the ld hl, n (sp) and ld hl, n (ix) instructions. */
2227           int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2228           int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
2229           if ((IS_RAB || IS_TLCS90) && aop->size - offset >= 2 && (aop->type == AOP_STK || aop->type == AOP_EXSTK)
2230               && (pairId == PAIR_HL || pairId == PAIR_IY || pairId == PAIR_DE) && (abs (fp_offset) <= 127 && pairId == PAIR_HL
2231                   && aop->type == AOP_STK
2232                   || abs (sp_offset) <= 127))
2233             {
2234               if (pairId == PAIR_DE)
2235                 {
2236                   emit2 ("ex de, hl");
2237                   regalloc_dry_run_cost += 1;
2238                 }
2239               if (abs (sp_offset) <= 127)
2240                 emit2 ("ld %s, %d (sp)", pairId == PAIR_IY ? "iy" : "hl", sp_offset);   /* Fetch relative to stack pointer. */
2241               else
2242                 emit2 ("ld hl, %d (ix)", fp_offset);    /* Fetch relative to frame pointer. */
2243               regalloc_dry_run_cost += (pairId == PAIR_IY ? 3 : 2);
2244               if (pairId == PAIR_DE)
2245                 {
2246                   emit2 ("ex de, hl");
2247                   regalloc_dry_run_cost += 1;
2248                 }
2249             }
2250           /* Operand resides (partially) in the pair */
2251           else if (!regalloc_dry_run && !strcmp (aopGet (aop, offset + 1, FALSE), _pairs[pairId].l))    // aopGet (aop, offset + 1, FALSE) is problematic: It prevents calculation of exact cost, and results in redundant code being generated. Todo: Exact cost
2252             {
2253               _moveA3 (aop, offset);
2254               if (!regalloc_dry_run)
2255                 emit2 ("ld %s, %s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
2256               regalloc_dry_run_cost += ld_cost (ASMOP_A, aop);
2257               emit2 ("ld %s, a", _pairs[pairId].l);
2258               regalloc_dry_run_cost += 1;
2259             }
2260           /* The Rabbit's cast to bool is a cheap way of zeroing h (similar to xor a, a for a for the Z80). */
2261           else if (pairId == PAIR_HL && IS_RAB && aop->size - offset == 1 && !(aop->type == AOP_REG && (aop->aopu.aop_reg[offset]->rIdx == L_IDX || aop->aopu.aop_reg[offset]->rIdx == H_IDX)))
2262             {
2263               emit2 ("bool hl");
2264               regalloc_dry_run_cost++;
2265               if (!regalloc_dry_run)
2266                 emit2 ("ld %s, %s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
2267               regalloc_dry_run_cost += ld_cost (ASMOP_L, aop);
2268             }
2269           else
2270             {
2271               if (!aopInReg (aop, offset, _pairs[pairId].l_idx))
2272                 {
2273                    if (!regalloc_dry_run)
2274                      emit2 ("ld %s, %s", _pairs[pairId].l, aopGet (aop, offset, FALSE));
2275                    regalloc_dry_run_cost += ld_cost (ASMOP_L, aop);
2276                 }
2277               if (!aopInReg (aop, offset + 1, _pairs[pairId].h_idx))
2278                 {
2279                    if (!regalloc_dry_run)
2280                      emit2 ("ld %s, %s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
2281                    regalloc_dry_run_cost += ld_cost (ASMOP_H, aop);
2282                 }
2283             }
2284         }
2285       /* PENDING: check? */
2286       spillPair (pairId);
2287     }
2288 }
2289 
2290 static void
fetchPair(PAIR_ID pairId,asmop * aop)2291 fetchPair (PAIR_ID pairId, asmop *aop)
2292 {
2293   fetchPairLong (pairId, aop, NULL, 0);
2294 }
2295 
2296 static void
setupPairFromSP(PAIR_ID id,int offset)2297 setupPairFromSP (PAIR_ID id, int offset)
2298 {
2299   wassertl (id == PAIR_HL || id == PAIR_DE || id == PAIR_IY, "Setup relative to SP only implemented for HL, DE, IY");
2300 
2301   if (_G.preserveCarry)
2302     {
2303       _push (PAIR_AF);
2304       regalloc_dry_run_cost++;
2305       offset += 2;
2306     }
2307 
2308   if (id == PAIR_DE && !IS_GB) // TODO: Could hl be in use for gbz80, so it needs to be saved and restored?
2309     {
2310       emit2 ("ex de, hl");
2311       regalloc_dry_run_cost++;
2312     }
2313 
2314   if (offset < INT8MIN || offset > INT8MAX || id == PAIR_IY)
2315     {
2316       struct dbuf_s dbuf;
2317       PAIR_ID lid = (id == PAIR_DE) ? PAIR_HL : id;
2318       dbuf_init (&dbuf, sizeof(int) * 3 + 1);
2319       dbuf_printf (&dbuf, "%d", offset);
2320       emit2 ("ld %s, !hashedstr", _pairs[lid].name, dbuf_c_str (&dbuf));
2321       dbuf_destroy (&dbuf);
2322       emit2 ("add %s, sp", _pairs[lid].name);
2323       regalloc_dry_run_cost += 4 + (id == PAIR_IY) * 2;
2324     }
2325   else
2326     {
2327       wassert (id == PAIR_DE || id == PAIR_HL);
2328       emit2 ("!ldahlsp", offset);
2329       regalloc_dry_run_cost += 4 - IS_GB * 2;
2330     }
2331 
2332   if (id == PAIR_DE && !IS_GB)
2333     {
2334       emit2 ("ex de, hl");
2335       regalloc_dry_run_cost++;
2336     }
2337   else if (id == PAIR_DE)
2338     {
2339       genMovePairPair (PAIR_HL, PAIR_DE);
2340       spillPair (PAIR_HL);
2341     }
2342 
2343   if (_G.preserveCarry)
2344     {
2345       _pop (PAIR_AF);
2346       regalloc_dry_run_cost++;
2347       offset -= 2;
2348     }
2349 }
2350 
2351 static void
2352 shiftIntoPair (PAIR_ID id, asmop *aop);
2353 
2354 /*-----------------------------------------------------------------*/
2355 /* pointPairToAop() make a register pair point to a byte of an aop */
2356 /*-----------------------------------------------------------------*/
pointPairToAop(PAIR_ID pairId,const asmop * aop,int offset)2357 static void pointPairToAop (PAIR_ID pairId, const asmop *aop, int offset)
2358 {
2359   switch (aop->type)
2360     {
2361     case AOP_EXSTK:
2362       wassertl (!IS_GB, "The GBZ80 doesn't have an extended stack");
2363 
2364     case AOP_STK:
2365       ; int abso = aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2366 
2367       if ((_G.pairs[pairId].last_type == AOP_STK || _G.pairs[pairId].last_type == AOP_EXSTK) && abs (_G.pairs[pairId].offset - abso) < 3)
2368         adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
2369       else
2370         setupPairFromSP (pairId, abso + _G.stack.pushed);
2371 
2372       _G.pairs[pairId].offset = abso;
2373 
2374       break;
2375 
2376     case AOP_HL: // Legacy.
2377       fetchLitPair (pairId, (asmop *) aop, offset);
2378       _G.pairs[pairId].offset = offset;
2379       break;
2380 
2381     case AOP_PAIRPTR:
2382       wassert (!offset);
2383 
2384       shiftIntoPair (pairId, (asmop *) aop); // Legacy. Todo eliminate uses of shiftIntoPair() ?
2385 
2386       break;
2387 
2388     default:
2389       wassertl (0, "Unsupported aop type for pointPairToAop()");
2390     }
2391 
2392   _G.pairs[pairId].last_type = aop->type;
2393 }
2394 
2395 // Weird function. Sometimes offset is used, sometimes not.
2396 // Callers rely on that behaviour. Uses of this should be replaced
2397 // by pointPairToAop() above after the 3.7.0 release.
2398 static void
setupPair(PAIR_ID pairId,asmop * aop,int offset)2399 setupPair (PAIR_ID pairId, asmop *aop, int offset)
2400 {
2401   switch (aop->type)
2402     {
2403     case AOP_IY:
2404       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
2405       fetchLitPair (pairId, aop, 0);
2406       break;
2407 
2408     case AOP_HL:
2409       wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
2410 
2411       fetchLitPair (pairId, aop, offset);
2412       _G.pairs[pairId].offset = offset;
2413       break;
2414 
2415     case AOP_EXSTK:
2416       wassertl (!IS_GB, "The GBZ80 doesn't have an extended stack");
2417       wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
2418 
2419       {
2420         int offset = aop->aopu.aop_stk + _G.stack.offset;
2421 
2422         if (aop->aopu.aop_stk >= 0)
2423           offset += _G.stack.param_offset;
2424 
2425         if (_G.pairs[pairId].last_type == aop->type && abs(_G.pairs[pairId].offset - offset) <= 3)
2426           adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
2427         else
2428           {
2429             struct dbuf_s dbuf;
2430 
2431             /* PENDING: Do this better. */
2432             if (_G.preserveCarry)
2433               _push (PAIR_AF);
2434             dbuf_init (&dbuf, 128);
2435             dbuf_printf (&dbuf, "%d", offset + _G.stack.pushed);
2436             emit2 ("ld %s, !hashedstr", _pairs[pairId].name, dbuf_c_str (&dbuf));
2437             dbuf_destroy (&dbuf);
2438             emit2 ("add %s, sp", _pairs[pairId].name);
2439             _G.pairs[pairId].last_type = aop->type;
2440             _G.pairs[pairId].offset = offset;
2441             if (_G.preserveCarry)
2442               _pop (PAIR_AF);
2443           }
2444       }
2445       break;
2446 
2447     case AOP_STK:
2448     {
2449       /* Doesnt include _G.stack.pushed */
2450       int abso = aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2451 
2452       assert (pairId == PAIR_HL);
2453       /* In some cases we can still inc or dec hl */
2454       if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
2455         {
2456           adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
2457         }
2458       else
2459         {
2460           setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
2461         }
2462       _G.pairs[pairId].offset = abso;
2463       break;
2464     }
2465 
2466     case AOP_PAIRPTR:
2467       if (pairId != aop->aopu.aop_pairId)
2468         genMovePairPair (aop->aopu.aop_pairId, pairId);
2469       adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
2470       break;
2471 
2472     default:
2473       wassert (0);
2474     }
2475   _G.pairs[pairId].last_type = aop->type;
2476 }
2477 
2478 static void
emitLabelSpill(symbol * tlbl)2479 emitLabelSpill (symbol *tlbl)
2480 {
2481   emitLabel (tlbl);
2482   spillCached ();
2483 }
2484 
2485 /*-----------------------------------------------------------------*/
2486 /* aopGet - for fetching value of the aop                          */
2487 /*-----------------------------------------------------------------*/
2488 static const char *
aopGet(asmop * aop,int offset,bool bit16)2489 aopGet (asmop *aop, int offset, bool bit16)
2490 {
2491   static struct dbuf_s dbuf = { 0 };
2492 
2493   wassert_bt (!regalloc_dry_run);
2494 
2495   if (dbuf_is_initialized (&dbuf))
2496     {
2497       /* reuse the dynamically allocated buffer */
2498       dbuf_set_length (&dbuf, 0);
2499     }
2500   else
2501     {
2502       /* first time: initialize the dynamically allocated buffer */
2503       dbuf_init (&dbuf, 128);
2504     }
2505 
2506   /* offset is greater than size then zero */
2507   /* PENDING: this seems a bit screwed in some pointer cases. */
2508   if (offset > (aop->size - 1) && aop->type != AOP_LIT)
2509     {
2510       dbuf_tprintf (&dbuf, "!zero");
2511     }
2512   else
2513     {
2514       /* depending on type */
2515       switch (aop->type)
2516         {
2517         case AOP_DUMMY:
2518           dbuf_append_char (&dbuf, 'a');
2519           break;
2520 
2521         case AOP_IMMD:
2522           /* PENDING: re-target */
2523           if (bit16)
2524             dbuf_tprintf (&dbuf, "!immedword", aop->aopu.aop_immd);
2525           else
2526             {
2527               switch (offset)
2528                 {
2529                 case 2:
2530                   // dbuf_tprintf (&dbuf, "!bankimmeds", aop->aopu.aop_immd); Bank support not fully implemented yet.
2531                   dbuf_tprintf (&dbuf, "#0x00");
2532                   break;
2533 
2534                 case 1:
2535                   dbuf_tprintf (&dbuf, "!msbimmeds", aop->aopu.aop_immd);
2536                   break;
2537 
2538                 case 0:
2539                   dbuf_tprintf (&dbuf, "!lsbimmeds", aop->aopu.aop_immd);
2540                   break;
2541 
2542                 default:
2543                   dbuf_tprintf (&dbuf, "#0x00");
2544                 }
2545             }
2546           break;
2547 
2548         case AOP_DIR:
2549           wassert (IS_GB);
2550           emit2 ("ld a, (%s+%d)", aop->aopu.aop_dir, offset);
2551           regalloc_dry_run_cost += 3;
2552           dbuf_append_char (&dbuf, 'a');
2553           break;
2554 
2555         case AOP_SFR:
2556           wassertl (!IS_TLCS90, "TLCS-90 does not have a separate I/O space");
2557           if (IS_GB)
2558             {
2559               emit2 ("ldh a, (%s+%d)", aop->aopu.aop_dir, offset);
2560               regalloc_dry_run_cost += 2;
2561               dbuf_append_char (&dbuf, 'a');
2562             }
2563           else if (IS_RAB)
2564             {
2565               emit2 ("ioi");
2566               emit2 ("ld a, (%s)", aop->aopu.aop_dir);
2567               emit2 ("nop");    /* Workaround for Rabbit 2000 hardware bug. see TN302 for details. */
2568               dbuf_append_char (&dbuf, 'a');
2569             }
2570           else
2571             {
2572               /*.p.t.20030716 handling for i/o port read access for Z80 */
2573               if (aop->paged)
2574                 {
2575                   /* banked mode */
2576                   /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
2577                   emit2 ("ld a, !msbimmeds", aop->aopu.aop_dir);
2578                   emit2 ("in a, (!lsbimmeds)", aop->aopu.aop_dir);
2579                 }
2580               else if (z80_opts.port_mode == 180)
2581                 {
2582                   /* z180 in0/out0 mode */
2583                   emit2 ("in0 a, (%s)", aop->aopu.aop_dir);
2584                 }
2585               else
2586                 {
2587                   /* 8 bit mode */
2588                   emit2 ("in a, (%s)", aop->aopu.aop_dir);
2589                 }
2590 
2591               dbuf_append_char (&dbuf, 'a');
2592             }
2593           break;
2594 
2595         case AOP_REG:
2596           dbuf_append_str (&dbuf, aop->aopu.aop_reg[offset]->name);
2597           break;
2598 
2599         case AOP_HL:
2600           setupPair (PAIR_HL, aop, offset);
2601           dbuf_tprintf (&dbuf, "!*hl");
2602           break;
2603 
2604         case AOP_IY:
2605           wassert (!IS_GB);
2606           setupPair (PAIR_IY, aop, offset);
2607           dbuf_tprintf (&dbuf, "!*iyx", offset);
2608           break;
2609 
2610         case AOP_EXSTK:
2611           if (!IY_RESERVED)
2612             {
2613               wassert (!IS_GB);
2614               setupPair (PAIR_IY, aop, offset);
2615               dbuf_tprintf (&dbuf, "!*iyx", offset);
2616               break;
2617             }
2618 
2619         case AOP_STK:
2620           if (IS_GB || aop->type == AOP_EXSTK)
2621             {
2622               pointPairToAop (PAIR_HL, aop, offset);
2623               dbuf_tprintf (&dbuf, "!*hl");
2624             }
2625           else if (_G.omitFramePtr)
2626             {
2627               if (aop->aopu.aop_stk >= 0)
2628                 offset += _G.stack.param_offset;
2629               setupPair (PAIR_IX, aop, offset);
2630               dbuf_tprintf (&dbuf, "!*ixx", offset);
2631             }
2632           else
2633             {
2634               if (aop->aopu.aop_stk >= 0)
2635                 offset += _G.stack.param_offset;
2636               dbuf_tprintf (&dbuf, "!*ixx", aop->aopu.aop_stk + offset);
2637             }
2638           break;
2639 
2640         case AOP_CRY:
2641           wassertl (0, "Tried to fetch from a bit variable");
2642           break;
2643 
2644         case AOP_LIT:
2645           dbuf_append_str (&dbuf, aopLiteral (aop->aopu.aop_lit, offset));
2646           break;
2647 
2648         case AOP_STR:
2649           aop->coff = offset;
2650           dbuf_append_str (&dbuf, aop->aopu.aop_str[offset]);
2651           break;
2652 
2653         case AOP_PAIRPTR:
2654           setupPair (aop->aopu.aop_pairId, aop, offset);
2655           if (aop->aopu.aop_pairId == PAIR_IX)
2656             dbuf_tprintf (&dbuf, "!*ixx", offset);
2657           else if (aop->aopu.aop_pairId == PAIR_IY)
2658             dbuf_tprintf (&dbuf, "!*iyx", offset);
2659           else
2660             dbuf_printf (&dbuf, "(%s)", _pairs[aop->aopu.aop_pairId].name);
2661           break;
2662 
2663         default:
2664           dbuf_destroy (&dbuf);
2665           fprintf (stderr, "aop->type: %d\n", aop->type);
2666           wassertl (0, "aopGet got unsupported aop->type");
2667           exit (0);
2668         }
2669     }
2670   return dbuf_c_str (&dbuf);
2671 }
2672 
2673 static bool
isRegString(const char * s)2674 isRegString (const char *s)
2675 {
2676   if (!strcmp (s, "b") || !strcmp (s, "c") || !strcmp (s, "d") || !strcmp (s, "e") ||
2677       !strcmp (s, "a") || !strcmp (s, "h") || !strcmp (s, "l"))
2678     return TRUE;
2679   return FALSE;
2680 }
2681 
2682 static bool
isConstantString(const char * s)2683 isConstantString (const char *s)
2684 {
2685   /* This is a bit of a hack... */
2686   return (*s == '#' || *s == '$');
2687 }
2688 
2689 #define AOP(op) op->aop
2690 #define AOP_TYPE(op) AOP(op)->type
2691 #define AOP_SIZE(op) AOP(op)->size
2692 #define AOP_NEEDSACC(x) (AOP(x) && ((AOP_TYPE(x) == AOP_CRY) || (AOP_TYPE(x) == AOP_SFR)))
2693 #define AOP_IS_PAIRPTR(x, p) (AOP_TYPE (x) == AOP_PAIRPTR && AOP (x)->aopu.aop_pairId == p)
2694 
2695 static bool
canAssignToPtr(const char * s)2696 canAssignToPtr (const char *s)
2697 {
2698   if (isRegString (s))
2699     return TRUE;
2700   if (isConstantString (s))
2701     return TRUE;
2702   return FALSE;
2703 }
2704 
2705 static bool
canAssignToPtr3(const asmop * aop)2706 canAssignToPtr3 (const asmop *aop)
2707 {
2708   if (aop->type == AOP_REG)
2709     return (TRUE);
2710   if (aop->type == AOP_IMMD || aop->type == AOP_LIT)
2711     return (TRUE);
2712   return (FALSE);
2713 }
2714 
2715 /*-----------------------------------------------------------------*/
2716 /* aopPut - puts a string for a aop                                */
2717 /*-----------------------------------------------------------------*/
2718 static void
aopPut(asmop * aop,const char * s,int offset)2719 aopPut (asmop *aop, const char *s, int offset)
2720 {
2721   struct dbuf_s dbuf;
2722 
2723   wassert (!regalloc_dry_run);
2724 
2725   if (aop->size && offset > (aop->size - 1))
2726     {
2727       werror_bt (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got offset > aop->size");
2728       exit (0);
2729     }
2730 
2731   // PENDING
2732   dbuf_init (&dbuf, 128);
2733   dbuf_tprintf (&dbuf, s);
2734   s = dbuf_c_str (&dbuf);
2735 
2736   /* will assign value to value */
2737   /* depending on where it is of course */
2738   switch (aop->type)
2739     {
2740     case AOP_DUMMY:
2741       _moveA (s);               /* in case s is volatile */
2742       break;
2743 
2744     case AOP_DIR:
2745       /* Direct.  Hmmm. */
2746       wassert (IS_GB);
2747       if (strcmp (s, "a"))
2748         emit2 ("ld a, %s", s);
2749       emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
2750       break;
2751 
2752     case AOP_SFR:
2753       wassertl (!IS_TLCS90, "TLCS-90 does not have a separate I/O space");
2754       if (IS_GB)
2755         {
2756           //  wassert (IS_GB);
2757           if (strcmp (s, "a"))
2758             emit2 ("ld a, %s", s);
2759           emit2 ("ldh (%s+%d),a", aop->aopu.aop_dir, offset);
2760         }
2761       else if (IS_RAB)
2762         {
2763           if (strcmp (s, "a"))
2764             emit2 ("ld a, %s", s);
2765 
2766           /* LM 20110928: Need to fix to emit either "ioi" or "ioe"
2767            * (for internal vs. external I/O space
2768            */
2769           emit2 ("ioi");
2770           emit2 ("ld (%s),a", aop->aopu.aop_dir);
2771           emit2 ("nop");        /* Workaround for Rabbit 2000 hardware bug. see TN302 for details. */
2772         }
2773       else
2774         {
2775           /*.p.t.20030716 handling for i/o port read access for Z80 */
2776           if (aop->paged)
2777             {
2778               /* banked mode */
2779               if (aop->bcInUse)
2780                 emit2 ("push bc");
2781 
2782               if (strlen (s) != 1 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e' && s[0] != 'h' && s[0] != 'l'))
2783                 {
2784                   emit2 ("ld a, %s", s);
2785                   s = "a";
2786                 }
2787 
2788               emit2 ("ld bc,#%s", aop->aopu.aop_dir);
2789               emit2 ("out (c),%s", s);
2790 
2791               if (aop->bcInUse)
2792                 emit2 ("pop bc");
2793               else
2794                 spillPair (PAIR_BC);
2795             }
2796           else if (z80_opts.port_mode == 180)
2797             {
2798               /* z180 in0/out0 mode */
2799               emit2 ("ld a, %s", s);
2800               emit2 ("out0 (%s), a", aop->aopu.aop_dir);
2801             }
2802           else
2803             {
2804               /* 8 bit mode */
2805               if (strcmp (s, "a"))
2806                 emit2 ("ld a, %s", s);
2807               emit2 ("out (%s), a", aop->aopu.aop_dir);
2808             }
2809         }
2810       break;
2811 
2812     case AOP_REG:
2813       if (!strcmp (aop->aopu.aop_reg[offset]->name, s))
2814         ;
2815       else if (!strcmp (s, "!*hl"))
2816         emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
2817       else
2818         emit2 ("ld %s, %s", aop->aopu.aop_reg[offset]->name, s);
2819       spillPairReg (aop->aopu.aop_reg[offset]->name);
2820       break;
2821 
2822     case AOP_IY:
2823       wassert (!IS_GB);
2824       if (!canAssignToPtr (s))
2825         {
2826           emit2 ("ld a, %s", s);
2827           setupPair (PAIR_IY, aop, offset);
2828           emit2 ("ld !*iyx, a", offset);
2829         }
2830       else
2831         {
2832           setupPair (PAIR_IY, aop, offset);
2833           emit2 ("ld !*iyx, %s", offset, s);
2834         }
2835       break;
2836 
2837     case AOP_HL:
2838       //wassert (IS_GB);
2839       /* PENDING: for re-target */
2840       if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2841         {
2842           emit2 ("ld a, !*hl");
2843           s = "a";
2844         }
2845       else if (strstr (s, "(ix)") || strstr (s, "(iy)"))
2846         {
2847           emit2 ("ld a, %s", s);
2848           s = "a";
2849         }
2850       setupPair (PAIR_HL, aop, offset);
2851 
2852       emit2 ("ld !*hl, %s", s);
2853       break;
2854 
2855     case AOP_EXSTK:
2856       if(!IY_RESERVED)
2857         {
2858           wassert (!IS_GB);
2859           if (!canAssignToPtr (s))
2860             {
2861               emit2 ("ld a, %s", s);
2862               setupPair (PAIR_IY, aop, offset);
2863               emit2 ("ld !*iyx, a", offset);
2864             }
2865           else
2866             {
2867               setupPair (PAIR_IY, aop, offset);
2868               emit2 ("ld !*iyx, %s", offset, s);
2869             }
2870           break;
2871        }
2872 
2873     case AOP_STK:
2874       if (IS_GB || aop->type == AOP_EXSTK)
2875         {
2876           /* PENDING: re-target */
2877           if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
2878             {
2879               emit2 ("ld a, !*hl");
2880               s = "a";
2881             }
2882           pointPairToAop (PAIR_HL, aop, offset);
2883           if (!canAssignToPtr (s))
2884             {
2885               emit2 ("ld a, %s", s);
2886               emit2 ("ld !*hl, a");
2887             }
2888           else
2889             emit2 ("ld !*hl, %s", s);
2890         }
2891       else
2892         {
2893           if (aop->aopu.aop_stk >= 0)
2894             offset += _G.stack.param_offset;
2895           if (!canAssignToPtr (s))
2896             {
2897               emit2 ("ld a, %s", s);
2898               emit2 ("ld !*ixx, a", aop->aopu.aop_stk + offset);
2899             }
2900           else
2901             {
2902               emit2 ("ld !*ixx, %s", aop->aopu.aop_stk + offset, s);
2903             }
2904         }
2905       break;
2906 
2907     case AOP_CRY:
2908       /* if bit variable */
2909       if (!aop->aopu.aop_dir)
2910         {
2911           emit2 ("ld a, !zero");
2912           emit2 ("rla");
2913         }
2914       else
2915         {
2916           /* In bit space but not in C - cant happen */
2917           wassertl (0, "Tried to write into a bit variable");
2918         }
2919       break;
2920 
2921     case AOP_STR:
2922       aop->coff = offset;
2923       if (strcmp (aop->aopu.aop_str[offset], s))
2924         {
2925           emit2 ("ld %s, %s", aop->aopu.aop_str[offset], s);
2926         }
2927       spillPairReg (aop->aopu.aop_str[offset]);
2928       break;
2929 
2930 #if 0
2931     case AOP_ACC:
2932       aop->coff = offset;
2933       if (!offset && (strcmp (s, "acc") == 0))
2934         break;
2935       if (offset > 0)
2936         {
2937           wassertl (0, "Tried to access past the end of A");
2938         }
2939       else
2940         {
2941           wassert (aop->aopu.aop_str[offset]);
2942           wassert (s);
2943           if (strcmp (aop->aopu.aop_str[offset], s))
2944             {
2945               emit2 ("ld %s, %s", aop->aopu.aop_str[offset], s);
2946               spillPairReg (aop->aopu.aop_str[offset]);
2947             }
2948         }
2949       break;
2950 #endif
2951 
2952     case AOP_PAIRPTR:
2953       setupPair (aop->aopu.aop_pairId, aop, offset);
2954       if (aop->aopu.aop_pairId == PAIR_IX)
2955         emit2 ("ld !*ixx, %s", 0, s);
2956       else if (aop->aopu.aop_pairId == PAIR_IY)
2957         emit2 ("ld !*iyx, %s", 0, s);
2958       else
2959         emit2 ("ld (%s), %s", _pairs[aop->aopu.aop_pairId].name, s);
2960       break;
2961 
2962     default:
2963       dbuf_destroy (&dbuf); fprintf (stderr, "AOP_DIR: %d\n",AOP_DIR);
2964       fprintf (stderr, "aop->type: %d\n", aop->type);
2965       werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type");
2966       exit (0);
2967     }
2968   dbuf_destroy (&dbuf);
2969 }
2970 
2971 // Move, but try not to. Cannot use xor to zero, since xor resets the carry flag.
2972 static void
cheapMove(asmop * to,int to_offset,asmop * from,int from_offset,bool a_dead)2973 cheapMove (asmop *to, int to_offset, asmop *from, int from_offset, bool a_dead)
2974 {
2975   if (aopInReg (to, to_offset, A_IDX))
2976     a_dead = true;
2977 
2978   if (to->type == AOP_REG && from->type == AOP_REG)
2979     {
2980       if (to->aopu.aop_reg[to_offset] == from->aopu.aop_reg[from_offset])
2981         return;
2982       bool from_index = aopInReg (from, from_offset, IYL_IDX) || aopInReg (from, from_offset, IYH_IDX);
2983       bool to_index = aopInReg (to, to_offset, IYL_IDX)  || aopInReg (to, to_offset, IYH_IDX);
2984       bool index = to_index || from_index;
2985       if (!index || IS_EZ80_Z80)
2986         {
2987           bool a = aopInReg (to, to_offset, A_IDX) || aopInReg (from, from_offset, A_IDX);
2988           if (!regalloc_dry_run)
2989             aopPut (to, aopGet (from, from_offset, false), to_offset);
2990           regalloc_dry_run_cost += 1 + (IS_TLCS90 + !a) + index;
2991           return;
2992         }
2993       if (aopInReg (from, from_offset, IYL_IDX) && !to_index && a_dead)
2994         {
2995           _push(PAIR_IY);
2996           _pop (PAIR_AF);
2997           cheapMove (to, to_offset, ASMOP_A, 0, true);
2998           return;
2999         }
3000       if (from_index && !to_index && _G.stack.pushed + _G.stack.offset + 2 <= 127 && !_G.omitFramePtr)
3001         {
3002           _push(PAIR_IY);
3003           if (!regalloc_dry_run)
3004             emit2 ("ld %s, %d (ix)", aopGet (to, to_offset, false), _G.stack.pushed + _G.stack.offset);
3005           regalloc_dry_run_cost += 3;
3006           _pop(PAIR_IY);
3007           return;
3008         }
3009 
3010       // Can't do it (todo: implement something there - will be expensive though, probably at least 7B of code).
3011       regalloc_dry_run_cost += 100;
3012       wassert (regalloc_dry_run);
3013     }
3014 
3015   // Try to push to avoid setting up temporary stack pointer in hl or iy.
3016   if ((to->type == AOP_STK || to->type == AOP_EXSTK) && _G.omitFramePtr &&
3017     (aopInReg (to, to_offset, A_IDX) || aopInReg (to, to_offset, B_IDX) || aopInReg (to, to_offset, D_IDX) || aopInReg (to, to_offset, H_IDX) || aopInReg (to, to_offset, IYH_IDX)))
3018     {
3019       int fp_offset = to->aopu.aop_stk + to_offset + (to->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3020       int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
3021 
3022       if (!sp_offset)
3023         {
3024           emit2 ("inc sp");
3025           emit2 ("push %s", aopInReg (from, from_offset, A_IDX) ? "af" : (aopInReg (from, from_offset, B_IDX) ? "bc" : (aopInReg (from, from_offset, D_IDX) ? "de" : (aopInReg (from, from_offset, H_IDX) ? "hl" : "iy"))));
3026           emit2 ("inc sp");
3027           regalloc_dry_run_cost += 3 + aopInReg (from, from_offset, IYH_IDX);
3028           return;
3029         }
3030     }
3031 
3032   if (aopInReg (from, from_offset, A_IDX) && to->type == AOP_IY)
3033     {
3034       emit2 ("ld (%s+%d), a", to->aopu.aop_dir, to_offset);
3035       regalloc_dry_run_cost += 3;
3036     }
3037   else if (!aopInReg (to, to_offset, A_IDX) && !aopInReg (from, from_offset, A_IDX) && (from->type == AOP_DIR || from->type == AOP_SFR || to->type == AOP_IY && from->type == AOP_EXSTK)) // Go through a.
3038     {
3039       if (!a_dead)
3040         _push (PAIR_AF);
3041 
3042       cheapMove (ASMOP_A, 0, from, from_offset, true);
3043       cheapMove (to, to_offset, ASMOP_A, 0, true);
3044 
3045       if (!a_dead)
3046         _pop (PAIR_AF);
3047     }
3048   else
3049     {
3050       if (!regalloc_dry_run)
3051         aopPut (to, aopGet (from, from_offset, false), to_offset);
3052 
3053       regalloc_dry_run_cost += ld_cost (to, from_offset < from->size ? from : ASMOP_ZERO);
3054     }
3055 }
3056 
3057 static void
commitPair(asmop * aop,PAIR_ID id,const iCode * ic,bool dont_destroy)3058 commitPair (asmop *aop, PAIR_ID id, const iCode *ic, bool dont_destroy)
3059 {
3060   int fp_offset = aop->aopu.aop_stk + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3061   int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
3062 
3063   if (getPairId (aop) == id)
3064     return;
3065 
3066   /* Stack positions will change, so do not assume this is possible in the cost function. */
3067   if (!regalloc_dry_run && !IS_GB && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && !sp_offset
3068       && ((!IS_RAB && id == PAIR_HL) || id == PAIR_IY) && !dont_destroy)
3069     {
3070       emit2 ("ex (sp), %s", _pairs[id].name);
3071       regalloc_dry_run_cost += ((id == PAIR_IY || IS_RAB) ? 2 : 1);
3072       spillPair (id);
3073     }
3074   else if ((IS_RAB || IS_TLCS90) && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (id == PAIR_HL || id == PAIR_IY) &&
3075            (id == PAIR_HL && abs (fp_offset) <= 127 && aop->type == AOP_STK || abs (sp_offset) <= 127))
3076     {
3077       if (abs (sp_offset) <= 127)
3078         emit2 ("ld %d (sp), %s", sp_offset, id == PAIR_IY ? "iy" : "hl");       /* Relative to stack pointer. */
3079       else
3080         emit2 ("ld %d (ix), hl", fp_offset);    /* Relative to frame pointer. */
3081       regalloc_dry_run_cost += (id == PAIR_HL ? 2 : 3);
3082     }
3083   else if (IS_EZ80_Z80 && aop->type == AOP_STK)
3084     {
3085       emit2 ("ld %d (ix), %s", fp_offset, _pairs[id].name);
3086       regalloc_dry_run_cost += 3;
3087     }
3088   else if (!regalloc_dry_run && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && !sp_offset)
3089     {
3090       emit2 ("inc sp");
3091       emit2 ("inc sp");
3092       emit2 ("push %s", _pairs[id].name);
3093       regalloc_dry_run_cost += (id == PAIR_IY ? 5 : 4);
3094     }
3095 
3096   /* PENDING: Verify this. */
3097   else if (id == PAIR_HL && requiresHL (aop) && (IS_GB || IY_RESERVED && aop->type != AOP_HL && aop->type != AOP_IY))
3098     {
3099       if (bitVectBitValue (ic->rSurv, D_IDX))
3100         _push (PAIR_DE);
3101       if (!regalloc_dry_run)
3102         {
3103           emit2 ("ld a, l");
3104           emit2 ("ld d, h");
3105           aopPut (aop, "a", 0);
3106           aopPut (aop, "d", 1);
3107         }
3108       regalloc_dry_run_cost += (2 + ld_cost (aop, ASMOP_A) + ld_cost (aop, ASMOP_D));
3109       if (bitVectBitValue (ic->rSurv, D_IDX))
3110         _pop (PAIR_DE);
3111     }
3112   else
3113     {
3114       /* Special cases */
3115       if ((aop->type == AOP_IY || aop->type == AOP_HL) && !IS_GB && aop->size == 2)
3116         {
3117           if (!regalloc_dry_run)
3118             {
3119               emit2 ("ld (%s), %s", aopGetLitWordLong (aop, 0, FALSE), _pairs[id].name);
3120             }
3121           regalloc_dry_run_cost += (id == PAIR_HL ? 3 : 4);
3122         }
3123       else
3124         {
3125           switch (id)
3126             {
3127             case PAIR_BC:
3128               cheapMove (aop, 0, ASMOP_C, 0, true);
3129               cheapMove (aop, 1, ASMOP_B, 0, true);
3130               break;
3131             case PAIR_DE:
3132               if (!IS_GB && aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == L_IDX && aop->aopu.aop_reg[1]->rIdx == H_IDX && !dont_destroy)
3133                 {
3134                   emit2 ("ex de, hl");
3135                   regalloc_dry_run_cost++;
3136                 }
3137               else
3138                 {
3139                   cheapMove (aop, 0, ASMOP_E, 0, true);
3140                   cheapMove (aop, 1, ASMOP_D, 0, true);
3141                 }
3142               break;
3143             case PAIR_HL:
3144               if (aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == H_IDX && aop->aopu.aop_reg[1]->rIdx == L_IDX)
3145                 {
3146                   cheapMove (ASMOP_A, 0, ASMOP_L, 0, true);
3147                   cheapMove (aop, 1, ASMOP_H, 0, true);
3148                   cheapMove (aop, 0, ASMOP_A, 0, true);
3149                 }
3150               else if (aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == H_IDX)     // Do not overwrite upper byte.
3151                 {
3152                   cheapMove (aop, 1, ASMOP_H, 0, true);
3153                   cheapMove (aop, 0, ASMOP_L, 0, true);
3154                 }
3155               else if (!IS_GB && aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == E_IDX && aop->aopu.aop_reg[1]->rIdx == D_IDX && !dont_destroy)
3156                 {
3157                   emit2 ("ex de, hl");
3158                   regalloc_dry_run_cost++;
3159                 }
3160               else
3161                 {
3162                   cheapMove (aop, 0, ASMOP_L, 0, true);
3163                   cheapMove (aop, 1, ASMOP_H, 0, true);
3164                 }
3165               break;
3166             case PAIR_IY:
3167               cheapMove (aop, 0, ASMOP_IYL, 0, true);
3168               cheapMove (aop, 1, ASMOP_IYH, 0, true);
3169               break;
3170             default:
3171               wassertl (0, "Unknown pair id in commitPair()");
3172               fprintf (stderr, "pair %s\n", _pairs[id].name);
3173             }
3174         }
3175     }
3176 }
3177 
3178 /*-----------------------------------------------------------------*/
3179 /* genCopyStack - Copy the value - stack to stack only             */
3180 /*-----------------------------------------------------------------*/
3181 static void
genCopyStack(asmop * result,int roffset,asmop * source,int soffset,int n,bool * assigned,int * size,bool a_free,bool hl_free,bool really_do_it_now)3182 genCopyStack (asmop *result, int roffset, asmop *source, int soffset, int n, bool *assigned, int *size, bool a_free, bool hl_free, bool really_do_it_now)
3183 {
3184   for (int i = 0; i < n;)
3185     {
3186       if (assigned[i])
3187         {
3188           i++;
3189           continue;
3190         }
3191 
3192       if (!aopOnStack (result, roffset + i, 1) || !aopOnStack (source, soffset + i, 1))
3193         {
3194           i++;
3195           continue;
3196         }
3197 
3198       if (i + 1 < n && !assigned[i + 1] && hl_free && (IS_RAB || IS_EZ80_Z80 || IS_TLCS90))
3199         {
3200           if (!regalloc_dry_run)
3201             {
3202               emit2 ("ld hl, %s", aopGet (source, soffset + i, false));
3203               emit2 ("ld %s, hl", aopGet (result, roffset + i, false));
3204             }
3205           cost2 (6 - 2 * IS_RAB, 0, 0, 22, 0, 21, 10);
3206 
3207           spillPair (PAIR_HL);
3208 
3209           assigned[i] = true;
3210           assigned[i + 1] = true;
3211           (*size) -= 2;
3212           i += 2;
3213           continue;
3214         }
3215 
3216       if (a_free || really_do_it_now)
3217         {
3218           cheapMove (result, roffset + i, source, soffset + i, a_free);
3219           assigned[i] = true;
3220           (*size)--;
3221           i++;
3222           continue;
3223         }
3224 
3225        i++;
3226     }
3227 
3228   wassertl_bt (*size >= 0, "genCopyStack() copied more than there is to be copied.");
3229 }
3230 
3231 /*-----------------------------------------------------------------*/
3232 /* genCopy - Copy the value from one reg/stk asmop to another      */
3233 /*-----------------------------------------------------------------*/
3234 static void
genCopy(asmop * result,int roffset,asmop * source,int soffset,int sizex,bool a_dead,bool hl_dead)3235 genCopy (asmop *result, int roffset, asmop *source, int soffset, int sizex, bool a_dead, bool hl_dead)
3236 {
3237   int regsize, size, n = (sizex < source->size - soffset) ? sizex : (source->size - soffset);
3238   bool assigned[8] = {false, false, false, false, false, false, false, false};
3239   bool a_free, hl_free;
3240   int cached_byte = -1;
3241   bool pushed_a = false;
3242 
3243   wassertl_bt (n <= 8, "Invalid size for genCopy().");
3244   wassertl_bt (aopRS (source), "Invalid source type.");
3245   wassertl_bt (aopRS (result), "Invalid result type.");
3246 
3247   size = n;
3248   regsize = 0;
3249   for (int i = 0; i < n; i++)
3250     regsize += (source->type == AOP_REG);
3251 
3252   // Do nothing for coalesced bytes.
3253   for (int i = 0; i < n; i++)
3254     if (result->type == AOP_REG && source->type == AOP_REG && result->aopu.aop_reg[roffset + i] == source->aopu.aop_reg[soffset + i])
3255       {
3256         assigned[i] = true;
3257         regsize--;
3258         size--;
3259       }
3260 
3261   // Move everything from registers to the stack.
3262   for (int i = 0; i < n;)
3263     {
3264       if (i + 1 < n && result->type == AOP_STK &&
3265         (aopInReg (source, soffset + i, HL_IDX) && IS_RAB ||
3266         (aopInReg (source, soffset + i, BC_IDX) || aopInReg (source, soffset + i, DE_IDX) || aopInReg (source, soffset + i, HL_IDX) || aopInReg (source, soffset + i, IY_IDX)) && (IS_EZ80_Z80 || IS_TLCS90)))
3267         {
3268           if (!regalloc_dry_run)
3269             emit2 ("ld %s, %s", aopGet (result, roffset + i, false), _pairs[getPairId_o (source, soffset + i)].name);
3270           cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5);
3271           assigned[i] = true;
3272           assigned[i + 1] = true;
3273           regsize -= 2;
3274           size -= 2;
3275           i += 2;
3276         }
3277       else if (aopRS (source) && !aopOnStack (source, soffset + i, 1) && aopOnStack (result, roffset + i, 1))
3278         {
3279           cheapMove (result, roffset + i, source, soffset + i, true);
3280           assigned[i] = true;
3281           regsize--;
3282           size--;
3283           i++;
3284         }
3285       else // This byte is not a register-to-stack copy.
3286         i++;
3287     }
3288 
3289   // Copy (stack-to-stack) what we can with whatever free regs we have.
3290   a_free = a_dead;
3291   hl_free = hl_dead;
3292   for (int i = 0; i < n; i++)
3293     {
3294       asmop *operand;
3295       int offset;
3296 
3297       if (!assigned[i])
3298         {
3299           operand = source;
3300           offset = soffset + i;
3301         }
3302       else
3303         {
3304           operand = result;
3305           offset = roffset + i;
3306         }
3307 
3308       if (aopInReg (operand, offset, A_IDX))
3309         a_free = false;
3310       else if (aopInReg (operand, offset, L_IDX) || aopInReg (operand, offset, H_IDX))
3311         hl_free = FALSE;
3312     }
3313   genCopyStack (result, roffset, source, soffset, n, assigned, &size, a_free, hl_free, false);
3314 
3315   // Now do the register shuffling.
3316 
3317   // Try to use:
3318   // TLCS-90 ld rr, rr
3319   // eZ80 lea rr, iy.
3320   // All: push rr / pop iy
3321   // All: push iy / pop rr
3322   for (int i = 0; i + 1 < n; i++)
3323     {
3324       if (assigned[i] || assigned[i + 1])
3325         continue;
3326 
3327       for (int j = 0; j + 1 < n; j++)
3328         {
3329           if (!assigned[j] && i != j && i + 1 != j && !aopOnStack(result, roffset + i, 2) && !aopOnStack(source, soffset + i, 1) &&
3330             (result->aopu.aop_reg[roffset + i] == source->aopu.aop_reg[soffset + j] || result->aopu.aop_reg[roffset + i + 1] == source->aopu.aop_reg[soffset + j]))
3331             goto skip_byte_push_iy; // We can't write this one without overwriting the source.
3332         }
3333 
3334       if (IS_TLCS90 && getPairId_o (result, roffset + i) != PAIR_INVALID && getPairId_o (source, soffset + i) != PAIR_INVALID)
3335         {
3336           emit2 ("ld %s, %s", _pairs[getPairId_o (result, roffset + i)].name, _pairs[getPairId_o (source, soffset + i)].name);
3337           regalloc_dry_run_cost += 1 + (!aopInReg (result, roffset + i, HL_IDX) && !aopInReg (source, soffset + i, HL_IDX));
3338         }
3339       else if (IS_EZ80_Z80 && getPairId_o (result, roffset + i) != PAIR_INVALID && aopInReg (source, soffset + i, IY_IDX))
3340         {
3341           emit2 ("lea %s, iy, #0", _pairs[getPairId_o (result, roffset + i)].name);
3342           regalloc_dry_run_cost += 3;
3343         }
3344       else if (aopInReg (result, roffset + i, IY_IDX) && getPairId_o (source, soffset + i) != PAIR_INVALID ||
3345         getPairId_o (result, roffset + i) != PAIR_INVALID && aopInReg (source, soffset + i, IY_IDX))
3346         {
3347           emit2 ("push %s", _pairs[getPairId_o (source, soffset + i)].name);
3348           emit2 ("pop %s", _pairs[getPairId_o (result, roffset + i)].name);
3349           regalloc_dry_run_cost += 3;
3350         }
3351       else
3352         continue;
3353 
3354       regsize -= 2;
3355       size -= 2;
3356       assigned[i] = true;
3357       assigned[i + 1] = true;
3358 
3359 skip_byte_push_iy:
3360         ;
3361     }
3362 
3363   // Try to use ex de, hl. TODO: Also do so when only some bytes are used, while others are dead (useful e.g. for emulating ld de, hl or ld hl, de).
3364   if (regsize >= 4)
3365     {
3366       int ex[4] = {-2, -2, -2, -2};
3367 
3368       // Find L and check that it is exchanged with E, find H and check that it is exchanged with D.
3369       for (int i = 0; i < n; i++)
3370         {
3371           if (!assigned[i] && aopInReg (result, roffset + i, L_IDX) && aopInReg (source, soffset + i, E_IDX))
3372             ex[0] = i;
3373           if (!assigned[i] && aopInReg (result, roffset + i, E_IDX) && aopInReg (source, soffset + i, L_IDX))
3374             ex[1] = i;
3375           if (!assigned[i] && aopInReg (result, roffset + i, H_IDX) && aopInReg (source, soffset + i, D_IDX))
3376             ex[2] = i;
3377           if (!assigned[i] && aopInReg (result, roffset + i, D_IDX) && aopInReg (source, soffset + i, H_IDX))
3378             ex[3] = i;
3379         }
3380 
3381       int exsum = (ex[0] >= 0) + (ex[1] >= 0) + (ex[2] >= 0) + (ex[3] >= 0);
3382 
3383       if (exsum == 4)
3384         {
3385           emit2 ("ex de, hl");
3386           regalloc_dry_run_cost += 1; // TODO: Use cost() to enable better optimization for speed.
3387           if(ex[0] >= 0)
3388             assigned[ex[0]] = TRUE;
3389           if(ex[1] >= 0)
3390             assigned[ex[1]] = TRUE;
3391           if(ex[2] >= 0)
3392             assigned[ex[2]] = TRUE;
3393           if(ex[3] >= 0)
3394             assigned[ex[3]] = TRUE;
3395           regsize -= exsum;
3396           size -= exsum;
3397         }
3398     }
3399 
3400   while (regsize && result->type == AOP_REG && source->type == AOP_REG)
3401     {
3402       int i;
3403 
3404       // Find lowest byte that can be assigned and needs to be assigned.
3405       for (i = 0; i < n; i++)
3406         {
3407           if (assigned[i])
3408             continue;
3409 
3410           for (int j = 0; j < n; j++)
3411             {
3412               if (!assigned[j] && i != j && result->aopu.aop_reg[roffset + i] == source->aopu.aop_reg[soffset + j])
3413                 goto skip_byte; // We can't write this one without overwriting the source.
3414             }
3415 
3416           break;                // Found byte that can be written safely.
3417 
3418 skip_byte:
3419           ;
3420         }
3421 
3422       if (i < n)
3423         {
3424           cheapMove (result, roffset + i, source, soffset + i, false);       // We can safely assign a byte.
3425           regsize--;
3426           size--;
3427           assigned[i] = true;
3428           continue;
3429         }
3430 
3431       // No byte can be assigned safely (i.e. the assignment is a permutation). Cache one in the accumulator.
3432 
3433       if (cached_byte != -1)
3434         {
3435           // Already one cached. Can happen when the assignment is a permutation consisting of multiple cycles.
3436           cheapMove (result, roffset + cached_byte, ASMOP_A, 0, true);
3437           cached_byte = -1;
3438           continue;
3439         }
3440 
3441       for (i = 0; i < n; i++)
3442         if (!assigned[i])
3443           break;
3444 
3445       wassertl_bt (i != n, "genCopy error: Trying to cache non-existant byte in accumulator.");
3446       if (a_free && !pushed_a)
3447         {
3448           _push (PAIR_AF);
3449           pushed_a = TRUE;
3450         }
3451       cheapMove (ASMOP_A, 0, source, soffset + i, true);
3452       regsize--;
3453       size--;
3454       assigned[i] = TRUE;
3455       cached_byte = i;
3456     }
3457 
3458   // Copy (stack-to-stack) what we can with whatever free regs we have now.
3459   a_free = a_dead;
3460   hl_free = hl_dead;
3461   for (int i = 0; i < n; i++)
3462     {
3463       if (!assigned[i])
3464         continue;
3465       if (aopInReg (result, roffset + i, A_IDX))
3466         a_free = false;
3467       else if (aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, H_IDX))
3468         hl_free = false;
3469     }
3470   genCopyStack (result, roffset, source, soffset, n, assigned, &size, a_free, hl_free, false);
3471 
3472   // Last, move everything from stack to registers.
3473   for (int i = 0; i < n;)
3474     {
3475       if (i + 1 < n && source->type == AOP_STK &&
3476         (aopInReg (result, roffset + i, HL_IDX) && IS_RAB ||
3477         (aopInReg (result, roffset + i, BC_IDX) || aopInReg (result, roffset + i, DE_IDX) || aopInReg (result, roffset + i, HL_IDX) || aopInReg (result, roffset + i, IY_IDX)) && (IS_EZ80_Z80 || IS_TLCS90)))
3478         {
3479           if (!regalloc_dry_run)
3480             emit2 ("ld %s, %s", _pairs[getPairId_o (result, roffset + i)].name, aopGet (source, soffset + i, false));
3481           cost2 (3 - IS_RAB, 0, 0, 11, 0, 9, 5);
3482           assigned[i] = true;
3483           assigned[i + 1] = true;
3484           size -= 2;
3485           i += 2;
3486         }
3487       else if (aopRS (result) && aopOnStack (source, soffset + i, 1) && !aopOnStack (result, roffset + i, 1))
3488         {
3489           cheapMove (result, roffset + i, source, soffset + i, true);
3490           assigned[i] = true;
3491           size--;
3492           i++;
3493         }
3494       else // This byte is not a register-to-stack copy.
3495         i++;
3496     }
3497 
3498   // Free a reg to copy (stack-to-stack) whatever is left.
3499   if (size)
3500     {
3501       a_free = a_dead && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= roffset + source->size);
3502       hl_free = a_dead && (result->regs[L_IDX] < 0 || result->regs[L_IDX] >= roffset + source->size) && (result->regs[H_IDX] < 0 || result->regs[H_IDX] >= roffset + source->size);
3503       if (!a_free)
3504         _push (PAIR_AF);
3505       genCopyStack (result, roffset, source, soffset, n, assigned, &size, true, hl_free, true);
3506       if (!a_free)
3507         _pop (PAIR_AF);
3508     }
3509 
3510   wassertl_bt (size >= 0, "genCopy() copied more than there is to be copied.");
3511 
3512   a_free = a_dead && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= roffset + source->size);
3513 
3514   // Place leading zeroes.
3515 
3516   // todo
3517 
3518   if (cached_byte != -1)
3519     cheapMove (result, roffset + cached_byte, ASMOP_A, 0, true);
3520 
3521   if (pushed_a)
3522     _pop (PAIR_AF);
3523 }
3524 
3525 /*-----------------------------------------------------------------*/
3526 /* genMove_o - Copy part of one asmop to another                   */
3527 /*-----------------------------------------------------------------*/
3528 static void
genMove_o(asmop * result,int roffset,asmop * source,int soffset,int size,bool a_dead_global,bool hl_dead_global)3529 genMove_o (asmop *result, int roffset, asmop *source, int soffset, int size, bool a_dead_global, bool hl_dead_global)
3530 {
3531   emitDebug ("; genMove_o");
3532 
3533   if ((result->type == AOP_REG || !IS_GB && result->type == AOP_STK) && (source->type == AOP_REG || !IS_GB && source->type == AOP_STK))
3534     {
3535       int csize = size > source->size - soffset ? source->size - soffset : size;
3536       genCopy (result, roffset, source, soffset, csize, a_dead_global, hl_dead_global);
3537       roffset += csize;
3538       size -= csize;
3539       genMove_o (result, roffset, ASMOP_ZERO, 0, size, a_dead_global && result->regs[A_IDX] < roffset, hl_dead_global && result->regs[H_IDX] < roffset && result->regs[L_IDX] < roffset);
3540       return;
3541     }
3542 
3543   bool zeroed_a = false;
3544   long value_hl = -1;
3545   bool a_dead = a_dead_global;
3546   bool hl_dead = hl_dead_global;
3547   for (unsigned int i = 0; i < size;)
3548     {
3549       if ((IS_EZ80_Z80 || IS_RAB || IS_TLCS90) && i + 1 < size && result->type == AOP_STK &&
3550         source->type == AOP_LIT && (value_hl >= 0 && aopIsLitVal (source, soffset + i, 2, value_hl) || hl_dead))
3551         {
3552           if (value_hl < 0 || !aopIsLitVal (source, soffset + i, 2, value_hl))
3553             fetchLitPair (PAIR_HL, source, soffset + i);
3554           if (!regalloc_dry_run)
3555             emit2 ("ld %s, hl", aopGet (result, roffset + i, false));
3556           cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5);
3557           regalloc_dry_run_cost += 3;
3558           value_hl = ullFromVal (source->aopu.aop_lit) >> ((soffset + i) * 8) & 0xffff;
3559           i += 2;
3560           continue;
3561         }
3562 
3563       // Cache a copy of zero in a.
3564       if (result->type != AOP_REG && aopIsLitVal (source, soffset + i, 2, 0x0000) && !zeroed_a && a_dead)
3565         {
3566           emit3 (A_XOR, ASMOP_A, ASMOP_A);
3567           regalloc_dry_run_cost += 1;
3568           zeroed_a = true;
3569         }
3570 
3571       if (result->type == AOP_HL && a_dead_global && (!hl_dead_global || source->regs[L_IDX] != -1 || source->regs[H_IDX] != -1))
3572         {
3573           if (!aopIsLitVal (source, soffset + i, 1, 0x00) || !zeroed_a)
3574             {
3575               cheapMove (ASMOP_A, 0, source, soffset + i, true);
3576               zeroed_a = aopIsLitVal (source, soffset + i, 1, 0x00);
3577             }
3578           emit2 ("ld (%s), a", aopGetLitWordLong (result, roffset + i, FALSE));
3579           regalloc_dry_run_cost += 3;
3580         }
3581       else if (aopIsLitVal (source, soffset + i, 1, 0x00) && zeroed_a)
3582         cheapMove (result, roffset + i, ASMOP_A, 0, false);
3583       else if (aopIsLitVal (source, soffset + i, 1, 0x00) && aopInReg (result, roffset + i, A_IDX))
3584         {
3585           emit3 (A_XOR, ASMOP_A, ASMOP_A);
3586           regalloc_dry_run_cost += 1;
3587           zeroed_a = true;
3588         }
3589       else
3590         {
3591           cheapMove (result, roffset + i, source, soffset + i, a_dead_global);
3592           zeroed_a = false;
3593         }
3594 
3595       if (aopInReg (result, roffset + i, A_IDX))
3596         a_dead = false;
3597       if (aopInReg (result, roffset + i, H_IDX) || aopInReg (result, roffset + i, L_IDX))
3598         hl_dead = false;
3599 
3600       i++;
3601     }
3602 }
3603 
3604 /*-----------------------------------------------------------------*/
3605 /* genMove - Copy the value from one asmop to another              */
3606 /*-----------------------------------------------------------------*/
3607 static void
genMove(asmop * result,asmop * source,bool a_dead,bool hl_dead)3608 genMove (asmop *result, asmop *source, bool a_dead, bool hl_dead)
3609 {
3610   genMove_o (result, 0, source, 0, result->size, a_dead, hl_dead);
3611 }
3612 
3613 /*-----------------------------------------------------------------*/
3614 /* getDataSize - get the operand data size                         */
3615 /*-----------------------------------------------------------------*/
3616 static int
getDataSize(operand * op)3617 getDataSize (operand * op)
3618 {
3619   int size;
3620   size = AOP_SIZE (op);
3621   if (size == 3)
3622     {
3623       /* pointer */
3624       wassertl (0, "Somehow got a three byte data pointer");
3625     }
3626   return size;
3627 }
3628 
3629 /*--------------------------------------------------------------------------*/
3630 /* adjustStack - Adjust the stack pointer by n bytes.                       */
3631 /*--------------------------------------------------------------------------*/
3632 static void
adjustStack(int n,bool af_free,bool bc_free,bool hl_free,bool iy_free)3633 adjustStack (int n, bool af_free, bool bc_free, bool hl_free, bool iy_free)
3634 {
3635   _G.stack.pushed -= n;
3636 
3637   if (IS_TLCS90 && abs(n) > (optimize.codeSize ? 2 + (af_free || bc_free || hl_free || iy_free || n < 0) * 2: 1))
3638     {
3639       emit2 ("add sp, #%d", n);
3640       cost (3, 6);
3641       n -= n;
3642     }
3643   else if (abs(n) > ((IS_RAB || IS_GB) ? 127 * 4 - 1 : (optimize.codeSize ? 8 : 5)) && hl_free)
3644     {
3645       spillCached ();
3646       emit2 ("ld hl, #%d", n);
3647       emit2 ("add hl, sp");
3648       emit2 ("ld sp, hl");
3649       cost2 (5, 27, 20, 10, 28, 18, 4);
3650       regalloc_dry_run_cost += 5;
3651       n -= n;
3652     }
3653   else if (!IS_GB && abs(n) > ((IS_RAB || IS_GB) ? 127 * 4 - 1 : 8) && iy_free)
3654     {
3655       spillCached ();
3656       emit2 ("ld iy, #%d", n);
3657       emit2 ("add iy, sp");
3658       emit2 ("ld sp, iy");
3659       regalloc_dry_run_cost += 8;
3660       n -= n;
3661     }
3662   else if (abs(n) > ((IS_RAB || IS_GB) ? 127 * 4 - 1 : 8) && bc_free)
3663     {
3664       emit2 ("ld c, l");
3665       emit2 ("ld b, h");
3666       emit2 ("ld hl, #%d", n);
3667       emit2 ("add hl, sp");
3668       emit2 ("ld sp, hl");
3669       emit2 ("ld l, c");
3670       emit2 ("ld h, b");
3671       regalloc_dry_run_cost += 9;
3672       n -= n;
3673     }
3674 
3675   while (abs(n))
3676     {
3677       if ((IS_RAB || IS_GB) && abs(n) > (optimize.codeSize ? 2 : 1))
3678         {
3679           int d;
3680           if (n > 127)
3681             d = 127;
3682           else if (n < -128)
3683             d = -128;
3684           else
3685             d = n;
3686           emit2 ("add sp, #%d", d);
3687           cost (2, IS_GB ? 16 : 4);
3688           n -= d;
3689         }
3690       else if (n >= 2 && af_free && (IS_Z80 || optimize.codeSize))
3691         {
3692           emit2 ("pop af");
3693           cost2 (1, 10, 9, 7, 12, 10, 3);
3694           n -= 2;
3695         }
3696       else if (n <= -2 && (IS_Z80 || optimize.codeSize))
3697         {
3698           emit2 ("push af");
3699           cost2 (1, 10, 11, 7, 12, 10, 3);
3700           n += 2;
3701         }
3702       else if (n >= 2 && bc_free && (IS_Z80 || optimize.codeSize))
3703         {
3704           emit2 ("pop bc");
3705           cost2 (1, 10, 9, 7, 12, 10, 3);
3706           n -= 2;
3707         }
3708       else if (n >= 2 && hl_free && (IS_Z80 || optimize.codeSize))
3709         {
3710           emit2 ("pop hl");
3711           cost2 (1, 10, 9, 7, 12, 10, 3);
3712           n -= 2;
3713         }
3714       else if (IS_TLCS90 && n >= 2 && iy_free && optimize.codeSize)
3715         {
3716           emit2 ("pop iy");
3717           cost (1, 10);
3718           n -= 2;
3719         }
3720       else if (n >= 1)
3721         {
3722           emit2 ("inc sp");
3723           cost2 (1, 6, 4, 2, 8, 4, 1);
3724           n--;
3725         }
3726       else if (n <= -1)
3727         {
3728           emit2 ("dec sp");
3729           cost2 (1, 6, 4, 2, 8, 4, 1);
3730           n++;
3731         }
3732     }
3733 
3734   wassert(!n);
3735 }
3736 
3737 /*-----------------------------------------------------------------*/
3738 /* movLeft2Result - move byte from left to result                  */
3739 /*-----------------------------------------------------------------*/
3740 static void
movLeft2Result(operand * left,int offl,operand * result,int offr,int sign)3741 movLeft2Result (operand *left, int offl, operand *result, int offr, int sign)
3742 {
3743   if (!sameRegs (AOP (left), AOP (result)) || (offl != offr))
3744     {
3745       if (!sign)
3746         cheapMove (AOP (result), offr, AOP (left), offl, true);
3747       else
3748         {
3749           if (getDataSize (left) == offl + 1)
3750             {
3751               cheapMove (ASMOP_A, 0, AOP (left), offl, true);
3752               cheapMove (AOP (result), offr, ASMOP_A, 0, true);
3753             }
3754         }
3755     }
3756 }
3757 
3758 /** Put Acc into a register set
3759  */
3760 static void
outAcc(operand * result)3761 outAcc (operand * result)
3762 {
3763   int size = getDataSize (result);
3764   if (size)
3765     {
3766       cheapMove (AOP (result), 0, ASMOP_A, 0, true);
3767       size--;
3768       genMove_o (result->aop, 1, ASMOP_ZERO, 0, size, true, false);
3769     }
3770 }
3771 
3772 /** Take the value in carry and put it into a register
3773  */
3774 static void
outBitC(operand * result)3775 outBitC (operand * result)
3776 {
3777   /* if the result is bit */
3778   if (AOP_TYPE (result) == AOP_CRY)
3779     {
3780       if (!IS_OP_RUONLY (result) && !regalloc_dry_run)
3781         aopPut (AOP (result), "c", 0);  // Todo: Cost.
3782     }
3783   else
3784     {
3785       emit2 ("ld a, !zero");
3786       emit2 ("rla");
3787       regalloc_dry_run_cost += 3;
3788       outAcc (result);
3789     }
3790 }
3791 
3792 /*-----------------------------------------------------------------*/
3793 /* toBoolean - emit code for or a,operator(sizeop)                 */
3794 /*-----------------------------------------------------------------*/
3795 static void
_toBoolean(const operand * oper,bool needflag)3796 _toBoolean (const operand *oper, bool needflag)
3797 {
3798   int size = AOP_SIZE (oper);
3799   sym_link *type = operandType (oper);
3800   int skipbyte;
3801 
3802   if (size == 1 && needflag)
3803     {
3804       cheapMove (ASMOP_A, 0, oper->aop, 0, true);
3805       emit3 (A_OR, ASMOP_A, ASMOP_A);
3806       return;
3807     }
3808 
3809   // Special handling to not overwrite a.
3810   if (oper->aop->regs[A_IDX] >= 0)
3811     skipbyte = oper->aop->regs[A_IDX];
3812   else
3813     {
3814       cheapMove (ASMOP_A, 0, oper->aop, size - 1, true);
3815       skipbyte = size - 1;
3816     }
3817 
3818   if (IS_FLOAT (type))
3819     {
3820       if (skipbyte != size - 1)
3821         {
3822           wassert (regalloc_dry_run);
3823           regalloc_dry_run_cost += 120;
3824         }
3825       emit2 ("res 7, a");   //clear sign bit
3826       regalloc_dry_run_cost += 2;
3827       skipbyte = size - 1;
3828     }
3829   while (size--)
3830     if (size != skipbyte)
3831       {
3832         if (aopInReg (oper->aop, size, IYL_IDX) || aopInReg (oper->aop, size, IYH_IDX))
3833           {
3834             regalloc_dry_run_cost += 100;
3835             wassert (regalloc_dry_run);
3836           }
3837         emit3_o (A_OR, ASMOP_A, 0, oper->aop, size);
3838       }
3839 }
3840 
3841 /*-----------------------------------------------------------------*/
3842 /* castBoolean - emit code for casting operand to boolean in a     */
3843 /*-----------------------------------------------------------------*/
3844 static void
_castBoolean(const operand * right)3845 _castBoolean (const operand *right)
3846 {
3847   emitDebug ("; Casting to bool");
3848 
3849   /* Can do without OR-ing for small arguments */
3850   if (AOP_SIZE (right) == 1 && !aopInReg (right->aop, 0, A_IDX))
3851     {
3852       emit3 (A_XOR, ASMOP_A, ASMOP_A);
3853       emit3 (A_CP, ASMOP_A, AOP (right));
3854     }
3855   else
3856     {
3857       _toBoolean (right, FALSE);
3858       emit2 ("add a, !immedbyte", 0xff);
3859       emit2 ("ld a, !zero");
3860       regalloc_dry_run_cost += 4;
3861     }
3862   emit2 ("rla");
3863   regalloc_dry_run_cost += 1;
3864 }
3865 
3866 /* Shuffle src reg array into dst reg array. */
3867 static void
regMove(const short * dst,const short * src,size_t n,bool preserve_a)3868 regMove (const short *dst, const short *src, size_t n, bool preserve_a)
3869 {
3870   bool assigned[9] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE };
3871   int cached_byte = -1;
3872   size_t size = n;
3873   int ex[4] = {-1, -1, -1, -1};
3874   size_t i;
3875   bool pushed_a = FALSE;
3876 
3877   wassert (n < 6);
3878 
3879   // Try to use ex de, hl
3880   if (size >= 4)
3881     {
3882       // Find E and check that it is exchanged with L.
3883       for (i = 0; i < n; i++)
3884         if (dst[i] == E_IDX && src[i] == L_IDX)
3885           ex[0] = i;
3886       for (i = 0; i < n; i++)
3887         if (dst[i] == L_IDX && src[i] == E_IDX)
3888           ex[1] = i;
3889       // Find D and check that it is exchanged with H.
3890       for (i = 0; i < n; i++)
3891         if (dst[i] == D_IDX && src[i] == H_IDX)
3892           ex[2] = i;
3893       for (i = 0; i < n; i++)
3894         if (dst[i] == H_IDX && src[i] == D_IDX)
3895           ex[3] = i;
3896       if (ex[0] >= 0 && ex[1] >= 0 && ex[2] >= 0 && ex[3] >= 0)
3897         {
3898           emit2 ("ex de, hl");
3899           regalloc_dry_run_cost++;
3900           assigned[ex[0]] = TRUE;
3901           assigned[ex[1]] = TRUE;
3902           assigned[ex[2]] = TRUE;
3903           assigned[ex[3]] = TRUE;
3904           size -= 4;
3905         }
3906     }
3907 
3908   // We need to be able to handle any assignment here, ensuring not to overwrite any parts of the source that we still need.
3909   while (size)
3910     {
3911       // Find lowest byte that can be assigned and needs to be assigned.
3912       for (i = 0; i < n; i++)
3913         {
3914           size_t j;
3915 
3916           if (assigned[i])
3917             continue;
3918 
3919           for (j = 0; j < n; j++)
3920             {
3921               if (!assigned[j] && i != j && dst[i] == src[j])
3922                 goto skip_byte; // We can't write this one without overwriting the source.
3923             }
3924 
3925           break;                // Found byte that can be written safely.
3926 
3927 skip_byte:
3928           ;
3929         }
3930 
3931       if (i < n)
3932         {
3933           cheapMove (asmopregs[dst[i]], 0, asmopregs[src[i]], 0, false);       // We can safely assign a byte.
3934           size--;
3935           assigned[i] = TRUE;
3936           continue;
3937         }
3938 
3939       // No byte can be assigned safely (i.e. the assignment is a permutation). Cache one in the accumulator.
3940 
3941       if (cached_byte != -1)
3942         {
3943           // Already one cached. Can happen when the assignment is a permutation consisting of multiple cycles.
3944           cheapMove (asmopregs[dst[cached_byte]], 0, ASMOP_A, 0, true);
3945           cached_byte = -1;
3946           continue;
3947         }
3948 
3949       for (i = 0; i < n; i++)
3950         if (!assigned[i])
3951           break;
3952 
3953       wassertl (i != n, "regMove error: Trying to cache non-existant byte in accumulator.");
3954       if (preserve_a && !pushed_a)
3955         {
3956           _push (PAIR_AF);
3957           pushed_a = TRUE;
3958         }
3959       cheapMove (ASMOP_A, 0, asmopregs[src[i]], 0, true);
3960       size--;
3961       assigned[i] = TRUE;
3962       cached_byte = i;
3963     }
3964 
3965   if (cached_byte != -1)
3966     cheapMove (asmopregs[dst[cached_byte]], 0, ASMOP_A, 0, true);
3967 
3968   if (pushed_a)
3969     _pop (PAIR_AF);
3970 }
3971 
3972 /*-----------------------------------------------------------------*/
3973 /* genNot - generate code for ! operation                          */
3974 /*-----------------------------------------------------------------*/
3975 static void
genNot(const iCode * ic)3976 genNot (const iCode * ic)
3977 {
3978   operand *left = IC_LEFT (ic);
3979   operand *result = IC_RESULT (ic);
3980 
3981   /* assign asmOps to operand & result */
3982   aopOp (left, ic, FALSE, TRUE);
3983   aopOp (result, ic, TRUE, FALSE);
3984 
3985   /* if in bit space then a special case */
3986   if (AOP_TYPE (left) == AOP_CRY)
3987     {
3988       wassertl (0, "Tried to negate a bit");
3989     }
3990   else if (IS_BOOL (operandType (left)))
3991     {
3992       cheapMove (ASMOP_A, 0, AOP (left), 0, true);
3993       emit2 ("xor a, !immedbyte", 0x01);
3994       regalloc_dry_run_cost += 2;
3995       cheapMove (AOP (result), 0, ASMOP_A, 0, true);
3996       goto release;
3997     }
3998 
3999   _toBoolean (left, FALSE);
4000 
4001   /* Not of A:
4002      If A == 0, !A = 1
4003      else A = 0
4004      So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
4005   emit2 ("sub a,!one");
4006   regalloc_dry_run_cost += 2;
4007   outBitC (result);
4008 
4009 release:
4010   /* release the aops */
4011   freeAsmop (left, NULL);
4012   freeAsmop (result, NULL);
4013 }
4014 
4015 /*-----------------------------------------------------------------*/
4016 /* genCpl - generate code for complement                           */
4017 /*-----------------------------------------------------------------*/
4018 static void
genCpl(const iCode * ic)4019 genCpl (const iCode *ic)
4020 {
4021   int skip_byte = -1;
4022 
4023   bool a_dead = !bitVectBitValue (ic->rSurv, A_IDX);
4024   bool pushed_a = false;
4025 
4026   /* assign asmOps to operand & result */
4027   aopOp (IC_LEFT (ic), ic, false, false);
4028   aopOp (IC_RESULT (ic), ic, true, false);
4029 
4030   /* if both are in bit space then
4031      a special case */
4032   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
4033     wassertl (0, "Left and the result are in bit space");
4034 
4035   int size = IC_RESULT (ic)->aop->size;
4036 
4037   if (IC_LEFT (ic)->aop->regs[A_IDX] >= 0 && IC_LEFT (ic)->aop->regs[A_IDX] < size)
4038     {
4039       int i = IC_LEFT (ic)->aop->regs[A_IDX];
4040       emit3 (A_CPL, 0, 0);
4041       cheapMove (IC_RESULT (ic)->aop, i, ASMOP_A, 0, true);
4042       skip_byte = i;
4043 
4044       if (aopInReg (IC_RESULT (ic)->aop, i, A_IDX))
4045         a_dead = false;
4046 
4047       // Do not overwrite still-needed value
4048       if (IC_RESULT (ic)->aop->type == AOP_REG && !aopInReg (IC_RESULT (ic)->aop, i, A_IDX))
4049         {
4050           int j = IC_LEFT (ic)->aop->regs[IC_RESULT (ic)->aop->aopu.aop_reg[i]->rIdx];
4051           if (j >= 0 && j != skip_byte && j < size)
4052             {
4053               regalloc_dry_run_cost += 150;
4054               wassert (regalloc_dry_run);
4055             }
4056         }
4057     }
4058 
4059   for (int i = 0; i < size; i++)
4060     {
4061       if (i == skip_byte)
4062         continue;
4063 
4064       if (!a_dead && !pushed_a)
4065         {
4066           _push (PAIR_AF);
4067           pushed_a = true;
4068         }
4069 
4070       cheapMove (ASMOP_A, 0, IC_LEFT (ic)->aop, i, true);
4071       emit3 (A_CPL, 0, 0);
4072       cheapMove (IC_RESULT (ic)->aop, i, ASMOP_A, 0, true);
4073 
4074       if (aopInReg (IC_RESULT (ic)->aop, i, A_IDX))
4075         a_dead = false;
4076 
4077       // Do not overwrite still-needed value
4078       if (IC_RESULT (ic)->aop->type == AOP_REG && !aopInReg (IC_RESULT (ic)->aop, i, A_IDX))
4079         {
4080           int j = IC_LEFT (ic)->aop->regs[IC_RESULT (ic)->aop->aopu.aop_reg[i]->rIdx];
4081           if (j > i && j < size && j != skip_byte)
4082             {
4083               regalloc_dry_run_cost += 150;
4084               wassert (regalloc_dry_run);
4085             }
4086         }
4087     }
4088 
4089   if (pushed_a)
4090     _pop (PAIR_AF);
4091 
4092   /* release the aops */
4093   freeAsmop (IC_LEFT (ic), 0);
4094   freeAsmop (IC_RESULT (ic), 0);
4095 }
4096 
4097 static void
_gbz80_emitAddSubLongLong(const iCode * ic,asmop * left,asmop * right,bool isAdd)4098 _gbz80_emitAddSubLongLong (const iCode * ic, asmop * left, asmop * right, bool isAdd)
4099 {
4100   enum asminst first = isAdd ? A_ADD : A_SUB;
4101   enum asminst later = isAdd ? A_ADC : A_SBC;
4102 
4103 
4104   /* Logic:
4105      ld de,right.lw
4106      setup hl to left
4107      de = hl - de
4108      push flags
4109      store de into result
4110      pop flags
4111      ld de,right.hw
4112      setup hl
4113      de = hl -de
4114      store de into result
4115    */
4116 
4117   wassertl (IS_GB, "Code is only relevant to the gbz80");
4118   wassertl (AOP (IC_RESULT (ic))->size == 4, "Only works for four bytes");
4119 
4120   fetchPair (PAIR_DE, left);
4121 
4122   emit2 ("ld a, e");
4123   regalloc_dry_run_cost += 1;
4124   emit3_o (first, ASMOP_A, 0, right, LSB);
4125   emit2 ("ld e, a");
4126   emit2 ("ld a, d");
4127   regalloc_dry_run_cost += 2;
4128   emit3_o (later, ASMOP_A, 0, right, MSB16);
4129 
4130   _push (PAIR_AF);
4131 
4132   cheapMove (AOP (IC_RESULT (ic)), MSB16, ASMOP_A, 0, true);
4133   cheapMove (AOP (IC_RESULT (ic)), LSB, ASMOP_E, 0, true);
4134 
4135   fetchPairLong (PAIR_DE, left, NULL, MSB24);
4136 
4137   if (!regalloc_dry_run)
4138     aopGet (right, MSB24, FALSE);
4139 
4140   _pop (PAIR_AF);
4141   emit2 ("ld a, e");
4142   emit3_o (later, ASMOP_A, 0, right, MSB24);
4143   emit2 ("ld e, a");
4144   emit2 ("ld a, d");
4145   regalloc_dry_run_cost += 2;
4146   emit3_o (later, ASMOP_A, 0, right, MSB32);
4147 
4148   cheapMove (AOP (IC_RESULT (ic)), MSB32, ASMOP_A, 0, true);
4149   cheapMove (AOP (IC_RESULT (ic)), MSB24, ASMOP_E, 0, true);
4150 }
4151 
4152 static void
_gbz80_emitAddSubLong(const iCode * ic,bool isAdd)4153 _gbz80_emitAddSubLong (const iCode * ic, bool isAdd)
4154 {
4155   _gbz80_emitAddSubLongLong (ic, AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)), isAdd);
4156 }
4157 
4158 /*-----------------------------------------------------------------*/
4159 /* assignResultValue -               */
4160 /*-----------------------------------------------------------------*/
4161 static void
assignResultValue(operand * oper)4162 assignResultValue (operand * oper)
4163 {
4164   int size = oper->aop->size;
4165 
4166   wassertl (size <= 4, "Got a result that is bigger than four bytes");
4167 
4168   if (IS_GB && size == 4 && requiresHL (AOP (oper)))
4169     {
4170       /* We do it the hard way here. */
4171       _push (PAIR_HL);
4172       cheapMove (oper->aop, 0, ASMOP_RETURN, 0, true);
4173       cheapMove (oper->aop, 1, ASMOP_RETURN, 1, true);
4174       _pop (PAIR_DE);
4175       cheapMove (oper->aop, 2, ASMOP_E, 0, true);
4176       cheapMove (oper->aop, 3, ASMOP_D, 0, true);
4177     }
4178   else
4179     genMove (oper->aop, ASMOP_RETURN, true, true);
4180 }
4181 
4182 /* Pop saved regs from stack, taking care not to destroy result */
4183 static void
restoreRegs(bool iy,bool de,bool bc,bool hl,const operand * result)4184 restoreRegs (bool iy, bool de, bool bc, bool hl, const operand *result)
4185 {
4186   bool bInRet, cInRet, dInRet, eInRet, hInRet, lInRet;
4187   bool SomethingReturned;
4188 
4189   SomethingReturned = (result && IS_ITEMP (result) &&
4190                       (OP_SYMBOL_CONST (result)->nRegs ||
4191                       OP_SYMBOL_CONST (result)->spildir ||
4192                       OP_SYMBOL_CONST (result)->accuse == ACCUSE_A)) || IS_TRUE_SYMOP (result);
4193 
4194   if (SomethingReturned)
4195     {
4196       bitVect *rv = z80_rUmaskForOp (result);
4197       bInRet = bitVectBitValue (rv, B_IDX);
4198       cInRet = bitVectBitValue (rv, C_IDX);
4199       dInRet = bitVectBitValue (rv, D_IDX);
4200       eInRet = bitVectBitValue (rv, E_IDX);
4201       hInRet = bitVectBitValue (rv, H_IDX);
4202       lInRet = bitVectBitValue (rv, L_IDX);
4203       freeBitVect (rv);
4204     }
4205   else
4206     {
4207       bInRet = FALSE;
4208       cInRet = FALSE;
4209       dInRet = FALSE;
4210       eInRet = FALSE;
4211       hInRet = FALSE;
4212       lInRet = FALSE;
4213     }
4214 
4215   if (iy)
4216     _pop (PAIR_IY);
4217 
4218   if (de)
4219     {
4220       if (dInRet && eInRet)
4221         wassertl (0, "Shouldn't push DE if it's wiped out by the return");
4222       else if (dInRet)
4223         {
4224           /* Only restore E */
4225           emit2 ("ld a, d");
4226           regalloc_dry_run_cost += 1;
4227           _pop (PAIR_DE);
4228           emit2 ("ld d, a");
4229           regalloc_dry_run_cost += 1;
4230         }
4231       else if (eInRet)
4232         {
4233           /* Only restore D */
4234           _pop (PAIR_AF);
4235           emit2 ("ld d, a");
4236           regalloc_dry_run_cost += 1;
4237         }
4238       else
4239         _pop (PAIR_DE);
4240     }
4241 
4242   if (bc)
4243     {
4244       if (bInRet && cInRet)
4245         wassertl (0, "Shouldn't push BC if it's wiped out by the return");
4246       else if (bInRet)
4247         {
4248           /* Only restore C */
4249           emit2 ("ld a, b");
4250           regalloc_dry_run_cost += 1;
4251           _pop (PAIR_BC);
4252           emit2 ("ld b, a");
4253           regalloc_dry_run_cost += 1;
4254         }
4255       else if (cInRet)
4256         {
4257           /* Only restore B */
4258           _pop (PAIR_AF);
4259           emit2 ("ld b, a");
4260           regalloc_dry_run_cost += 1;
4261         }
4262       else
4263         _pop (PAIR_BC);
4264     }
4265 
4266   if (hl)
4267     {
4268       if (hInRet && lInRet)
4269         wassertl (0, "Shouldn't push HL if it's wiped out by the return");
4270       else if (hInRet)
4271         {
4272           /* Only restore E */
4273           emit2 ("ld a, h");
4274           regalloc_dry_run_cost += 1;
4275           _pop (PAIR_HL);
4276           emit2 ("ld h, a");
4277           regalloc_dry_run_cost += 1;
4278         }
4279       else if (lInRet)
4280         {
4281           /* Only restore D */
4282           _pop (PAIR_AF);
4283           emit2 ("ld h, a");
4284           regalloc_dry_run_cost += 1;
4285         }
4286       else
4287         _pop (PAIR_HL);
4288     }
4289 }
4290 
4291 static void
_saveRegsForCall(const iCode * ic,bool dontsaveIY)4292 _saveRegsForCall (const iCode * ic, bool dontsaveIY)
4293 {
4294   /* Rules:
4295      o Stack parameters are pushed before this function enters
4296      o DE and BC may be used in this function.
4297      o HL and DE may be used to return the result.
4298      o HL and DE may be used to send variables.
4299      o DE and BC may be used to store the result value.
4300      o HL may be used in computing the sent value of DE
4301      o The iPushes for other parameters occur before any addSets
4302 
4303      Logic: (to be run inside the first iPush or if none, before sending)
4304      o Compute if DE, BC, HL, IY are in use over the call
4305      o Compute if DE is used in the send set
4306      o Compute if DE and/or BC are used to hold the result value
4307      o If (DE is used, or in the send set) and is not used in the result, push.
4308      o If BC is used and is not in the result, push
4309      o
4310      o If DE is used in the send set, fetch
4311      o If HL is used in the send set, fetch
4312      o Call
4313      o ...
4314    */
4315 
4316   sym_link *dtype = operandType (IC_LEFT (ic));
4317   sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype;
4318 
4319   if (_G.saves.saved == FALSE)
4320     {
4321       bool push_bc, push_de, push_hl, push_iy;
4322 
4323       if (options.oldralloc)
4324         {
4325           bool deInUse, bcInUse;
4326           bool bcInRet = FALSE, deInRet = FALSE;
4327           bitVect *rInUse;
4328 
4329           rInUse = bitVectCplAnd (bitVectCopy (ic->rMask), z80_rUmaskForOp (IC_RESULT (ic)));
4330 
4331           deInUse = bitVectBitValue (rInUse, D_IDX) || bitVectBitValue (rInUse, E_IDX);
4332           bcInUse = bitVectBitValue (rInUse, B_IDX) || bitVectBitValue (rInUse, C_IDX);
4333 
4334           emitDebug ("; _saveRegsForCall: deInUse: %u bcInUse: %u", deInUse, bcInUse);
4335 
4336           push_bc = bcInUse && !bcInRet;
4337           push_de = deInUse && !deInRet;
4338           push_hl = FALSE;
4339           push_iy = FALSE;
4340         }
4341       else
4342         {
4343           push_bc = bitVectBitValue (ic->rSurv, B_IDX) && !ftype->funcAttrs.preserved_regs[B_IDX] || bitVectBitValue (ic->rSurv, C_IDX) && !ftype->funcAttrs.preserved_regs[C_IDX];
4344           push_de = bitVectBitValue (ic->rSurv, D_IDX) && !ftype->funcAttrs.preserved_regs[D_IDX] || bitVectBitValue (ic->rSurv, E_IDX) && !ftype->funcAttrs.preserved_regs[E_IDX];
4345           push_hl = bitVectBitValue (ic->rSurv, H_IDX) || bitVectBitValue (ic->rSurv, L_IDX);
4346           push_iy = !dontsaveIY && (bitVectBitValue (ic->rSurv, IYH_IDX) || bitVectBitValue (ic->rSurv, IYL_IDX));
4347         }
4348 
4349       if (push_hl)
4350         {
4351           _push (PAIR_HL);
4352           _G.stack.pushedHL = TRUE;
4353         }
4354       if (push_bc)
4355         {
4356           _push (PAIR_BC);
4357           _G.stack.pushedBC = TRUE;
4358         }
4359       if (push_de)
4360         {
4361           _push (PAIR_DE);
4362           _G.stack.pushedDE = TRUE;
4363         }
4364       if (push_iy)
4365         {
4366           _push (PAIR_IY);
4367           _G.stack.pushedIY = TRUE;
4368         }
4369 
4370       if (!regalloc_dry_run)
4371         _G.saves.saved = TRUE;
4372     }
4373   else
4374     {
4375       /* Already saved. */
4376     }
4377 }
4378 
4379 /*-----------------------------------------------------------------*/
4380 /* genIpush - genrate code for pushing this gets a little complex  */
4381 /*-----------------------------------------------------------------*/
4382 static void
genIpush(const iCode * ic)4383 genIpush (const iCode *ic)
4384 {
4385   int size, offset = 0;
4386 
4387   /* if this is not a parm push : ie. it is spill push
4388      and spill push is always done on the local stack */
4389   if (!ic->parmPush)
4390     {
4391       wassertl (0, "Encountered an unsupported spill push.");
4392       return;
4393     }
4394 
4395   /* Scan ahead until we find the function that we are pushing parameters to.
4396      Count the number of addSets on the way to figure out what registers
4397      are used in the send set.
4398    */
4399   int nAddSets = 0;
4400   iCode *walk = ic->next;
4401 
4402   while (walk)
4403     {
4404       if (walk->op == SEND && !_G.saves.saved && !regalloc_dry_run)
4405         nAddSets++;
4406       else if (walk->op == CALL || walk->op == PCALL)
4407         break; // Found it.
4408 
4409       walk = walk->next; // Keep looking.
4410     }
4411   if (!regalloc_dry_run && !_G.saves.saved && !regalloc_dry_run) /* Cost is counted at CALL or PCALL instead */
4412     _saveRegsForCall (walk, false); /* Caller saves, and this is the first iPush. */
4413 
4414   const bool smallc = IFFUNC_ISSMALLC (operandType (IC_LEFT (walk)));
4415 
4416   /* then do the push */
4417   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4418 
4419   size = AOP_SIZE (IC_LEFT (ic));
4420 
4421   if (isPair (AOP (IC_LEFT (ic))) && size == 2)
4422     {
4423       if (!regalloc_dry_run)
4424         {
4425           _G.stack.pushed += 2;
4426           emit2 ("push %s", getPairName (AOP (IC_LEFT (ic))));
4427         }
4428       regalloc_dry_run_cost += (getPairId (AOP (IC_LEFT (ic))) == PAIR_IY ? 2 : 1);
4429     }
4430   else
4431     {
4432       if (size == 1 && smallc) /* The SmallC calling convention pushes 8-bit parameters as 16-bit values. */
4433         {
4434           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[2]->rIdx == C_IDX)
4435             {
4436               emit2 ("push bc");
4437               regalloc_dry_run_cost += 1;
4438             }
4439           else if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[2]->rIdx == E_IDX)
4440             {
4441               emit2 ("push de");
4442               regalloc_dry_run_cost += 1;
4443             }
4444           else if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[2]->rIdx == L_IDX)
4445             {
4446               emit2 ("push hl");
4447               regalloc_dry_run_cost += 1;
4448             }
4449           else
4450             {
4451               emit2 ("dec sp");
4452               cheapMove (ASMOP_A, 0, AOP (IC_LEFT (ic)), 0, true);
4453               emit2 ("push af");
4454               emit2 ("inc sp");
4455               regalloc_dry_run_cost += 3;
4456             }
4457           if (!regalloc_dry_run)
4458             _G.stack.pushed += 2;
4459           goto release;
4460         }
4461       else if (size == 2)
4462         {
4463           PAIR_ID pair = getDeadPairId (ic);
4464           if (pair == PAIR_INVALID || isPairDead (PAIR_HL, ic))
4465             pair = PAIR_HL;     /* hl sometimes is cheaper to load than other pairs. */
4466 
4467           fetchPairLong (pair, AOP (IC_LEFT (ic)), ic, 0);
4468           if (!regalloc_dry_run)
4469             {
4470               emit2 ("push %s", _pairs[pair].name);
4471               _G.stack.pushed += 2;
4472             }
4473           regalloc_dry_run_cost += 1;
4474           goto release;
4475         }
4476       if (size == 4)
4477         {
4478           if (getPairId_o (IC_LEFT (ic)->aop, 2) != PAIR_INVALID)
4479             {
4480               emit2 ("push %s", _pairs[getPairId_o (IC_LEFT (ic)->aop, 2)].name);
4481               regalloc_dry_run_cost += 1 + (getPairId_o (IC_LEFT (ic)->aop, 2) == PAIR_IY);
4482             }
4483           else
4484             {
4485               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, 2);
4486               emit2 ("push hl");
4487               regalloc_dry_run_cost += 1;
4488             }
4489           if (!regalloc_dry_run)
4490             _G.stack.pushed += 2;
4491 
4492           if (getPairId_o (IC_LEFT (ic)->aop, 0) != PAIR_INVALID)
4493             {
4494               emit2 ("push %s", _pairs[getPairId_o (IC_LEFT (ic)->aop, 0)].name);
4495               regalloc_dry_run_cost += 1 + (getPairId_o (IC_LEFT (ic)->aop, 2) == PAIR_IY);
4496             }
4497           else
4498             {
4499               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, 0);
4500               emit2 ("push hl");
4501               regalloc_dry_run_cost += 1;
4502             }
4503           if (!regalloc_dry_run)
4504             _G.stack.pushed += 2;
4505 
4506           goto release;
4507         }
4508       offset = size;
4509       while (size--)
4510         {
4511           if (size && getFreePairId (ic) != PAIR_INVALID)
4512             {
4513               offset -= 2;
4514 
4515               PAIR_ID pair = getFreePairId (ic);
4516               fetchPairLong (pair, AOP (IC_LEFT (ic)), 0, offset);
4517               emit2 ("push %s", _pairs[pair].name);
4518               regalloc_dry_run_cost += 1;
4519               size--;
4520 
4521               if (!regalloc_dry_run)
4522                 _G.stack.pushed += 2;
4523 
4524               continue;
4525             }
4526           else if (AOP (IC_LEFT (ic))->type == AOP_IY)
4527             {
4528               wassertl (!bitVectBitValue (ic->rSurv, A_IDX), "Loading from address destroys A, which must survive.");
4529               emit2 ("ld a, (%s)", aopGetLitWordLong (AOP (IC_LEFT (ic)), --offset, FALSE));
4530               emit2 ("push af");
4531               regalloc_dry_run_cost += 4;
4532             }
4533           else
4534             {
4535               offset--;
4536               if (AOP (IC_LEFT (ic))->type == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[offset]->rIdx == B_IDX)
4537                 {
4538                   emit2 ("push bc");
4539                   regalloc_dry_run_cost += 1;
4540                 }
4541               else if (AOP (IC_LEFT (ic))->type == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[offset]->rIdx == D_IDX)
4542                 {
4543                   emit2 ("push de");
4544                   regalloc_dry_run_cost += 1;
4545                 }
4546               else if (AOP (IC_LEFT (ic))->type == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[offset]->rIdx == H_IDX)
4547                 {
4548                   emit2 ("push hl");
4549                   regalloc_dry_run_cost += 1;
4550                 }
4551               else
4552                 {
4553                   if (AOP_TYPE (IC_LEFT (ic)) != AOP_SFR && !regalloc_dry_run && !strcmp (aopGet (AOP (IC_LEFT (ic)), offset, FALSE), "h"))   // todo: More exact cost!
4554                     emit2 ("push hl");
4555                   else
4556                     {
4557                       wassertl (aopInReg (IC_LEFT (ic)->aop, 0, A_IDX) || !bitVectBitValue (ic->rSurv, A_IDX), "Push operand destroys A, which must survive.");
4558                       if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT && byteOfVal (AOP (IC_LEFT (ic))->aopu.aop_lit, offset) == 0x00)
4559                         emit3 (A_XOR, ASMOP_A, ASMOP_A);
4560                       else
4561                         {
4562                           cheapMove (ASMOP_A, 0, AOP (IC_LEFT (ic)), offset, true);
4563                           if (!aopInReg (IC_LEFT (ic)->aop, 0, A_IDX))
4564                             regalloc_dry_run_cost += ld_cost (ASMOP_A, AOP (IC_LEFT (ic)));
4565                         }
4566                       emit2 ("push af");
4567                       regalloc_dry_run_cost += 1;
4568                     }
4569                 }
4570             }
4571           if (!regalloc_dry_run)
4572             {
4573               emit2 ("inc sp");
4574               _G.stack.pushed++;
4575             }
4576           regalloc_dry_run_cost += 1;
4577         }
4578     }
4579 release:
4580   freeAsmop (IC_LEFT (ic), NULL);
4581 }
4582 
4583 /*-----------------------------------------------------------------*/
4584 /* genIpop - recover the registers: can happen only for spilling   */
4585 /*-----------------------------------------------------------------*/
4586 static void
genIpop(const iCode * ic)4587 genIpop (const iCode * ic)
4588 {
4589   int size, offset;
4590 
4591   wassert (!regalloc_dry_run);
4592 
4593   /* if the temp was not pushed then */
4594   if (OP_SYMBOL (IC_LEFT (ic))->isspilt)
4595     return;
4596 
4597   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4598   size = AOP_SIZE (IC_LEFT (ic));
4599   offset = (size - 1);
4600   if (isPair (AOP (IC_LEFT (ic))))
4601     {
4602       emit2 ("pop %s", getPairName (AOP (IC_LEFT (ic))));
4603     }
4604   else
4605     {
4606       while (size--)
4607         {
4608           emit2 ("dec sp");
4609           emit2 ("pop hl");
4610           spillPair (PAIR_HL);
4611           aopPut (AOP (IC_LEFT (ic)), "l", offset--);
4612         }
4613     }
4614 
4615   freeAsmop (IC_LEFT (ic), NULL);
4616 }
4617 
4618 /* This is quite unfortunate */
4619 static void
setArea(int inHome)4620 setArea (int inHome)
4621 {
4622   /*
4623      static int lastArea = 0;
4624 
4625      if (_G.in_home != inHome) {
4626      if (inHome) {
4627      const char *sz = port->mem.code_name;
4628      port->mem.code_name = "HOME";
4629      emit2("!area", CODE_NAME);
4630      port->mem.code_name = sz;
4631      }
4632      else
4633      emit2("!area", CODE_NAME); */
4634   _G.in_home = inHome;
4635   //    }
4636 }
4637 
4638 static bool
isInHome(void)4639 isInHome (void)
4640 {
4641   return _G.in_home;
4642 }
4643 
4644 /** Emit the code for a register parameter
4645  */
genSend(const iCode * ic)4646 static void genSend (const iCode *ic)
4647 {
4648   int size;
4649 
4650   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
4651   size = AOP_SIZE (IC_LEFT (ic));
4652 
4653   wassertl (ic->next->op == CALL || ic->next->op == PCALL, "Sending register parameter for missing call");
4654   wassertl (!IS_GB, "Register parameters are not supported in gbz80 port");
4655 
4656   if (_G.saves.saved == FALSE && !regalloc_dry_run /* Cost is counted at CALL or PCALL instead */ )
4657     {
4658       /* Caller saves, and this is the first iPush. */
4659       /* Scan ahead until we find the function that we are pushing parameters to.
4660          Count the number of addSets on the way to figure out what registers
4661          are used in the send set.
4662        */
4663       int nAddSets = 0;
4664       iCode *walk = ic->next;
4665 
4666       while (walk)
4667         {
4668           if (walk->op == SEND)
4669             {
4670               nAddSets++;
4671             }
4672           else if (walk->op == CALL || walk->op == PCALL)
4673             {
4674               /* Found it. */
4675               break;
4676             }
4677           else
4678             {
4679               /* Keep looking. */
4680             }
4681           walk = walk->next;
4682         }
4683       _saveRegsForCall (walk, FALSE);
4684     }
4685   if (size == 2)
4686     {
4687       fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
4688       z80_regs_used_as_parms_in_calls_from_current_function[L_IDX] = true;
4689       z80_regs_used_as_parms_in_calls_from_current_function[H_IDX] = true;
4690     }
4691   else if (size <= 4)
4692     {
4693       if (size == 4 && ASMOP_RETURN->aopu.aop_reg[0]->rIdx == L_IDX && ASMOP_RETURN->aopu.aop_reg[1]->rIdx == H_IDX &&
4694         ASMOP_RETURN->aopu.aop_reg[2]->rIdx == E_IDX && ASMOP_RETURN->aopu.aop_reg[3]->rIdx == D_IDX)
4695         {
4696           if (!isPairDead (PAIR_DE, ic) && getPairId_o (AOP (IC_LEFT (ic)), 2) != PAIR_DE)
4697             {
4698               regalloc_dry_run_cost += 100;
4699               wassertl (regalloc_dry_run, "Register parameter overwrites value that is still needed");
4700             }
4701           fetchPairLong (PAIR_DE, AOP (IC_LEFT (ic)), ic, 2);
4702           z80_regs_used_as_parms_in_calls_from_current_function[E_IDX] = true;
4703           z80_regs_used_as_parms_in_calls_from_current_function[D_IDX] = true;
4704           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
4705           z80_regs_used_as_parms_in_calls_from_current_function[L_IDX] = true;
4706           z80_regs_used_as_parms_in_calls_from_current_function[H_IDX] = true;
4707         }
4708       else
4709         {
4710           for (int i = 0; i < AOP_SIZE (IC_LEFT (ic)); i++)
4711             if (!regalloc_dry_run)
4712               z80_regs_used_as_parms_in_calls_from_current_function[ASMOP_RETURN->aopu.aop_reg[i]->rIdx] = true;
4713 
4714           genMove_o (ASMOP_RETURN, 0, IC_LEFT (ic)->aop, 0, IC_LEFT (ic)->aop->size, true, true);
4715         }
4716     }
4717 
4718   freeAsmop (IC_LEFT (ic), NULL);
4719 }
4720 
4721 /** Emit the code for a call statement
4722  */
4723 static void
genCall(const iCode * ic)4724 genCall (const iCode *ic)
4725 {
4726   sym_link *dtype = operandType (IC_LEFT (ic));
4727   sym_link *etype = getSpec (dtype);
4728   sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype;
4729   int i;
4730   int prestackadjust = 0;
4731   bool tailjump = false;
4732 
4733   const bool z88dk_callee = IFFUNC_ISZ88DK_CALLEE (ftype);
4734 
4735   for (i = 0; i < IYH_IDX + 1; i++)
4736     z80_regs_preserved_in_calls_from_current_function[i] |= ftype->funcAttrs.preserved_regs[i];
4737 
4738   _saveRegsForCall (ic, FALSE);
4739 
4740   const bool bigreturn = (getSize (ftype->next) > 4); // Return value of big type or returning struct or union.
4741   const bool SomethingReturned = (IS_ITEMP (IC_RESULT (ic)) &&
4742                        (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
4743                         OP_SYMBOL (IC_RESULT (ic))->spildir ||
4744                         OP_SYMBOL (IC_RESULT (ic))->accuse == ACCUSE_A)) || IS_TRUE_SYMOP (IC_RESULT (ic));
4745 
4746   aopOp (IC_LEFT (ic), ic, false, false);
4747   if (SomethingReturned && !bigreturn)
4748     aopOp (IC_RESULT (ic), ic, false, false);
4749 
4750   if (bigreturn)
4751     {
4752       PAIR_ID pair;
4753       int fp_offset, sp_offset;
4754 
4755       if (ic->op == PCALL && IS_GB)
4756         _push (PAIR_HL);
4757       aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
4758       wassert (AOP_TYPE (IC_RESULT (ic)) == AOP_STK || AOP_TYPE (IC_RESULT (ic)) == AOP_EXSTK);
4759       fp_offset =
4760         AOP (IC_RESULT (ic))->aopu.aop_stk + (AOP (IC_RESULT (ic))->aopu.aop_stk >
4761             0 ? _G.stack.param_offset : 0);
4762       sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
4763       pair = (ic->op == PCALL && !IS_GB && !IY_RESERVED) ? PAIR_IY : PAIR_HL;
4764       emit2 ("ld %s, !immedword", _pairs[pair].name, sp_offset);
4765       emit2 ("add %s, sp", _pairs[pair].name);
4766       regalloc_dry_run_cost += (pair == PAIR_IY ? 6 : 4);
4767       if (ic->op == PCALL && IS_GB)
4768         {
4769           emit2 ("ld e, l");
4770           emit2 ("ld d, h");
4771           regalloc_dry_run_cost += 2;
4772           _pop (PAIR_HL);
4773           pair = PAIR_DE;
4774         }
4775       emit2 ("push %s", _pairs[pair].name);
4776       regalloc_dry_run_cost += (pair == PAIR_IY ? 2 : 1);
4777       if (!regalloc_dry_run)
4778         _G.stack.pushed += 2;
4779       freeAsmop (IC_RESULT (ic), NULL);
4780     }
4781   // Check if we can do tail call optimization.
4782   else if (!(currFunc && IFFUNC_ISISR (currFunc->type)) &&
4783     (!SomethingReturned || IC_RESULT (ic)->aop->size == 1 && aopInReg (IC_RESULT (ic)->aop, 0, IS_GB ? E_IDX : L_IDX) || IC_RESULT (ic)->aop->size == 2 && aopInReg (IC_RESULT (ic)->aop, 0, IS_GB ? DE_IDX : HL_IDX)) &&
4784     !ic->parmBytes && !ic->localEscapeAlive && !IFFUNC_ISBANKEDCALL (dtype) && !IFFUNC_ISZ88DK_SHORTCALL (ftype) && _G.omitFramePtr &&
4785     (ic->op != PCALL || !IFFUNC_ISZ88DK_FASTCALL (ftype)))
4786     {
4787       int limit = 16; // Avoid endless loops in the code putting us into an endless loop here.
4788 
4789       for (const iCode *nic = ic->next; nic && --limit;)
4790         {
4791           const symbol *targetlabel = 0;
4792 
4793           if (nic->op == LABEL)
4794             ;
4795           else if (nic->op == GOTO) // We dont have ebbi here, so we cant jsut use eBBWithEntryLabel (ebbi, ic->label). Search manually.
4796             targetlabel = IC_LABEL (nic);
4797           else if (nic->op == RETURN && (!IC_LEFT (nic) || SomethingReturned && IC_RESULT (ic)->key == IC_LEFT (nic)->key))
4798             targetlabel = returnLabel;
4799           else if (nic->op == ENDFUNCTION)
4800             {
4801               if (OP_SYMBOL (IC_LEFT (nic))->stack <= (ic->op == PCALL ? 1 : (optimize.codeSize ? 1 : 2)) + IS_RAB * 120)
4802                 {
4803                   prestackadjust = OP_SYMBOL (IC_LEFT (nic))->stack;
4804                   tailjump = true;
4805                 }
4806               break;
4807             }
4808           else
4809             break;
4810 
4811           if (targetlabel)
4812             {
4813               const iCode *nnic = 0;
4814               for (nnic = nic->next; nnic; nnic = nnic->next)
4815                 if (nnic->op == LABEL && IC_LABEL (nnic)->key == targetlabel->key)
4816                   break;
4817               if (!nnic)
4818                 for (nnic = nic->prev; nnic; nnic = nnic->prev)
4819                   if (nnic->op == LABEL && IC_LABEL (nnic)->key == targetlabel->key)
4820                     break;
4821               if (!nnic)
4822                 break;
4823 
4824               nic = nnic;
4825             }
4826           else
4827             nic = nic->next;
4828         }
4829     }
4830 
4831   const bool jump = tailjump || !ic->parmBytes && !bigreturn && ic->op != PCALL && !IFFUNC_ISBANKEDCALL (dtype) && !IFFUNC_ISZ88DK_SHORTCALL(ftype) && IFFUNC_ISNORETURN (ftype);
4832 
4833   if (ic->op == PCALL)
4834     {
4835       if (IFFUNC_ISBANKEDCALL (dtype))
4836         {
4837           werror (W_INDIR_BANKED);
4838         }
4839       else if (IFFUNC_ISZ88DK_SHORTCALL (ftype))
4840        {
4841           wassertl(0, "__z88dk_short_call via function pointer not implemented");
4842        }
4843 
4844       if (isLitWord (AOP (IC_LEFT (ic))))
4845         {
4846           adjustStack (prestackadjust, false, false, false, false);
4847           emit2 (jump ? "jp %s" : "call %s", aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
4848           regalloc_dry_run_cost += 3;
4849         }
4850       else if (getPairId (AOP (IC_LEFT (ic))) != PAIR_IY && !IFFUNC_ISZ88DK_FASTCALL (ftype))
4851         {
4852           spillPair (PAIR_HL);
4853           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
4854           adjustStack (prestackadjust, false, false, false, false);
4855           emit2 (jump ? "jp (hl)" : "call ___sdcc_call_hl");
4856           regalloc_dry_run_cost += 3;
4857         }
4858       else if (!IS_GB && !IY_RESERVED)
4859         {
4860           spillPair (PAIR_IY);
4861           fetchPairLong (PAIR_IY, IC_LEFT (ic)->aop, ic, 0);
4862           adjustStack (prestackadjust, false, false, false, false);
4863           emit2 (jump ? "jp (iy)" : "call ___sdcc_call_iy");
4864           regalloc_dry_run_cost += 3;
4865         }
4866       else // Use bc, since it is the only 16-bit register guarateed to be free even for __z88dk_fastcall with --reserve-regs-iy
4867         {
4868           wassert (!prestackadjust);
4869           wassert (IY_RESERVED); // The peephole optimizer handles ret for purposes other than returning only for --reserve-regs-iy
4870           if (aopInReg (IC_LEFT (ic)->aop, 0, B_IDX) || aopInReg (IC_LEFT (ic)->aop, 0, C_IDX) || aopInReg (IC_LEFT (ic)->aop, 1, B_IDX) || aopInReg (IC_LEFT (ic)->aop, 1, C_IDX))
4871             {
4872               regalloc_dry_run_cost += 100;
4873               wassertl (regalloc_dry_run, "Unimplemented function pointer in bc");
4874             }
4875           symbol *tlbl = 0;
4876           if (!regalloc_dry_run)
4877             {
4878               tlbl = newiTempLabel (NULL);
4879               emit2 ("ld bc, #!tlabel", labelKey2num (tlbl->key));
4880               emit2 ("push bc");
4881               regalloc_dry_run_cost += 4;
4882             }
4883           fetchPairLong (PAIR_BC, IC_LEFT (ic)->aop, 0, 0);
4884           emit2 ("push bc");
4885           emit2 ("ret");
4886           regalloc_dry_run_cost += 2;
4887           if (tlbl)
4888             emit2 ("!tlabeldef", labelKey2num (tlbl->key));
4889         }
4890     }
4891   else
4892     {
4893       /* make the call */
4894       if (IFFUNC_ISBANKEDCALL (dtype))
4895         {
4896           wassert (!prestackadjust);
4897 
4898           char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name;
4899           emit2 ("call banked_call");
4900           emit2 ("!dws", name);
4901           emit2 ("!dw !bankimmeds", name);
4902           regalloc_dry_run_cost += 6;
4903         }
4904       else
4905         {
4906           adjustStack (prestackadjust, false, false, false, false);
4907 
4908           if (IS_LITERAL (etype))
4909             {
4910               emit2 (jump ? "jp 0x%04X" : "call 0x%04X", ulFromVal (OP_VALUE (IC_LEFT (ic))));
4911               regalloc_dry_run_cost += 3;
4912             }
4913           else if (IFFUNC_ISZ88DK_SHORTCALL(ftype))
4914             {
4915               int rst = ftype->funcAttrs.z88dk_shortcall_rst;
4916               int value = ftype->funcAttrs.z88dk_shortcall_val;
4917               emit2 ("rst 0x%02x", rst);
4918               if ( value < 256 )
4919                 emit2 ("defb 0x%02x\n",value);
4920               else
4921                 emit2 ("defw 0x%04x\n",value);
4922               regalloc_dry_run_cost += 3;
4923             }
4924           else
4925             {
4926               emit2 ("%s %s", jump ? "jp" : "call",
4927                 (OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name));
4928               regalloc_dry_run_cost += 3;
4929             }
4930         }
4931     }
4932   spillCached ();
4933 
4934   freeAsmop (IC_LEFT (ic), 0);
4935 
4936   _G.stack.pushed += prestackadjust;
4937 
4938   /* Mark the registers as restored. */
4939   _G.saves.saved = FALSE;
4940 
4941   /* adjust the stack for parameters if required */
4942   if ((ic->parmBytes || bigreturn) && (IFFUNC_ISNORETURN (ftype) || z88dk_callee))
4943     {
4944       if (!regalloc_dry_run)
4945         {
4946           _G.stack.pushed -= (ic->parmBytes + bigreturn * 2);
4947           z80_symmParm_in_calls_from_current_function = FALSE;
4948         }
4949     }
4950   else if ((ic->parmBytes || bigreturn))
4951     {
4952       adjustStack (ic->parmBytes + bigreturn * 2, !IS_TLCS90, TRUE, !SomethingReturned || bigreturn, !IY_RESERVED);
4953 
4954       if (regalloc_dry_run)
4955         _G.stack.pushed += ic->parmBytes + bigreturn * 2;
4956     }
4957 
4958   /* if we need assign a result value */
4959   if (SomethingReturned && !bigreturn)
4960     {
4961       assignResultValue (IC_RESULT (ic));
4962 
4963       freeAsmop (IC_RESULT (ic), NULL);
4964     }
4965 
4966   spillCached ();
4967 
4968   restoreRegs (_G.stack.pushedIY, _G.stack.pushedDE, _G.stack.pushedBC, _G.stack.pushedHL, IC_RESULT (ic));
4969   _G.stack.pushedIY = FALSE;
4970   _G.stack.pushedDE = FALSE;
4971   _G.stack.pushedBC = FALSE;
4972   _G.stack.pushedHL = FALSE;
4973 }
4974 
4975 /*-----------------------------------------------------------------*/
4976 /* resultRemat - result  is rematerializable                       */
4977 /*-----------------------------------------------------------------*/
4978 static int
resultRemat(const iCode * ic)4979 resultRemat (const iCode * ic)
4980 {
4981   if (SKIP_IC (ic) || ic->op == IFX)
4982     return 0;
4983 
4984   if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
4985     {
4986       const symbol *sym = OP_SYMBOL_CONST (IC_RESULT (ic));
4987       if (sym->remat && !POINTER_SET (ic) && sym->isspilt)
4988         return 1;
4989     }
4990 
4991   return 0;
4992 }
4993 
4994 /*-----------------------------------------------------------------*/
4995 /* genFunction - generated code for function entry                 */
4996 /*-----------------------------------------------------------------*/
4997 static void
genFunction(const iCode * ic)4998 genFunction (const iCode * ic)
4999 {
5000   bool stackParm;
5001 
5002   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5003   sym_link *ftype;
5004 
5005   bool bcInUse = FALSE;
5006   bool deInUse = FALSE;
5007   bool bigreturn;
5008 
5009   setArea (IFFUNC_NONBANKED (sym->type));
5010   wassert (!_G.stack.pushed);
5011 
5012   /* PENDING: Reset the receive offset as it
5013      doesn't seem to get reset anywhere else.
5014    */
5015   _G.receiveOffset = 0;
5016   _G.stack.param_offset = sym->type->funcAttrs.z88dk_params_offset;
5017 
5018   /* Record the last function name for debugging. */
5019   _G.lastFunctionName = sym->rname;
5020 
5021   /* Create the function header */
5022   emit2 ("!functionheader", sym->name);
5023 
5024   emitDebug (z80_assignment_optimal ? "; Register assignment is optimal." : "; Register assignment might be sub-optimal.");
5025   emitDebug ("; Stack space usage: %d bytes.", sym->stack);
5026 
5027   if (IS_STATIC (sym->etype))
5028     emit2 ("!functionlabeldef", sym->rname);
5029   else
5030     emit2 ("!globalfunctionlabeldef", sym->rname);
5031 
5032   if (!regalloc_dry_run)
5033     genLine.lineCurr->isLabel = 1;
5034 
5035   ftype = operandType (IC_LEFT (ic));
5036 
5037   if (IFFUNC_ISNAKED (ftype))
5038     {
5039       emitDebug ("; naked function: no prologue.");
5040       return;
5041     }
5042 
5043   /* if this is an interrupt service routine
5044      then save all potentially used registers. */
5045   if (IFFUNC_ISISR (sym->type))
5046     {
5047       if (!IFFUNC_ISCRITICAL (sym->type))
5048         {
5049           emit2 ("!ei");
5050         }
5051 
5052       emit2 ("!pusha");
5053     }
5054   else
5055     {
5056       /* This is a non-ISR function.
5057          If critical function then turn interrupts off */
5058       if (IFFUNC_ISCRITICAL (sym->type))
5059         {
5060           if (IS_GB || IS_RAB || IS_TLCS90)
5061             {
5062               emit2 ("!di");
5063             }
5064           else
5065             {
5066               //get interrupt enable flag IFF2 into P/O
5067               emit2 ("ld a,i");
5068               emit2 ("!di");
5069               //save P/O flag
5070               emit2 ("push af");
5071               _G.stack.param_offset += 2;
5072             }
5073         }
5074     }
5075 
5076   if (options.profile)
5077     {
5078       emit2 ("!profileenter");
5079     }
5080 
5081   if (z80_opts.calleeSavesBC)
5082     {
5083       bcInUse = TRUE;
5084     }
5085 
5086   /* Detect which registers are used. */
5087   if (IFFUNC_CALLEESAVES (sym->type) && sym->regsUsed)
5088     {
5089       int i;
5090       for (i = 0; i < sym->regsUsed->size; i++)
5091         {
5092           if (bitVectBitValue (sym->regsUsed, i))
5093             {
5094               switch (i)
5095                 {
5096                 case C_IDX:
5097                 case B_IDX:
5098                   bcInUse = TRUE;
5099                   break;
5100                 case D_IDX:
5101                 case E_IDX:
5102                   if (!IS_GB)
5103                     {
5104                       deInUse = TRUE;
5105                     }
5106                   else
5107                     {
5108                       /* Other systems use DE as a temporary. */
5109                     }
5110                   break;
5111                 }
5112             }
5113         }
5114     }
5115 
5116   if (bcInUse)
5117     {
5118       emit2 ("push bc");
5119       _G.stack.param_offset += 2;
5120     }
5121 
5122   _G.calleeSaves.pushedBC = bcInUse;
5123 
5124   if (deInUse)
5125     {
5126       emit2 ("push de");
5127       _G.stack.param_offset += 2;
5128     }
5129 
5130   _G.calleeSaves.pushedDE = deInUse;
5131 
5132   /* adjust the stack for the function */
5133 //  _G.stack.last = sym->stack;
5134 
5135   bigreturn = (getSize (ftype->next) > 4);
5136   _G.stack.param_offset += bigreturn * 2;
5137 
5138   stackParm = FALSE;
5139   for (sym = setFirstItem (istack->syms); sym; sym = setNextItem (istack->syms))
5140     {
5141       if (sym->_isparm && !IS_REGPARM (sym->etype))
5142         {
5143           stackParm = TRUE;
5144           break;
5145         }
5146     }
5147   sym = OP_SYMBOL (IC_LEFT (ic));
5148 
5149   _G.omitFramePtr = options.oldralloc ? (!IS_GB && options.omitFramePtr) : should_omit_frame_ptr;
5150 
5151   if (!IS_GB && !z80_opts.noOmitFramePtr && !stackParm && !sym->stack)
5152     {
5153       if (!regalloc_dry_run)
5154         _G.omitFramePtr = TRUE;
5155     }
5156   else if (sym->stack)
5157     {
5158       if (!_G.omitFramePtr)
5159         emit2 ((optimize.codeSize && !IFFUNC_ISZ88DK_FASTCALL (ftype)) ? "!enters" : "!enter");
5160       if (IS_EZ80_Z80 && !_G.omitFramePtr && -sym->stack > -128 && -sym->stack <= -3 && !IFFUNC_ISZ88DK_FASTCALL (ftype))
5161         {
5162           emit2 ("lea hl, ix, #%d", -sym->stack);
5163           emit2 ("ld sp, hl");
5164           regalloc_dry_run_cost += 4;
5165         }
5166       else
5167         adjustStack (-sym->stack, !IS_TLCS90, TRUE, !IFFUNC_ISZ88DK_FASTCALL (ftype), !IY_RESERVED);
5168       _G.stack.pushed = 0;
5169     }
5170   else if (!_G.omitFramePtr)
5171     {
5172       emit2 ((optimize.codeSize && !IFFUNC_ISZ88DK_FASTCALL (ftype)) ? "!enters" : "!enter");
5173     }
5174 
5175   _G.stack.offset = sym->stack;
5176 }
5177 
5178 /*-----------------------------------------------------------------*/
5179 /* genEndFunction - generates epilogue for functions               */
5180 /*-----------------------------------------------------------------*/
5181 static void
genEndFunction(iCode * ic)5182 genEndFunction (iCode * ic)
5183 {
5184   symbol *sym = OP_SYMBOL (IC_LEFT (ic));
5185   int retsize = getSize (sym->type->next);
5186   /* __critical __interrupt without an interrupt number is the non-maskable interrupt */
5187   bool is_nmi = (IS_Z80 || IS_Z180 || IS_EZ80_Z80) && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO (sym->type) == INTNO_UNSPEC;
5188 
5189   wassert (!regalloc_dry_run);
5190   wassertl (!_G.stack.pushed, "Unbalanced stack.");
5191 
5192   if (IFFUNC_ISNAKED (sym->type) || IFFUNC_ISNORETURN (sym->type))
5193     {
5194       emitDebug (IFFUNC_ISNAKED (sym->type) ? "; naked function: No epilogue." : "; _Noreturn function: No epilogue.");
5195       return;
5196     }
5197 
5198   wassertl(regalloc_dry_run || !IFFUNC_ISZ88DK_CALLEE(sym->type), "Unimplemented __z88dk_callee support on callee side");
5199 
5200   if (!IS_GB && !_G.omitFramePtr && sym->stack > (optimize.codeSize ? 2 : 1))
5201     {
5202       emit2 ("ld sp, ix");
5203       cost2 (2, 10, 7, 4, 0, 6, 2);
5204     }
5205   else
5206     adjustStack (_G.stack.offset, !IS_TLCS90, TRUE, retsize == 0 || retsize > 4, !IY_RESERVED);
5207 
5208   if(!IS_GB && !_G.omitFramePtr)
5209     emit2 ("pop ix");
5210 
5211   if (_G.calleeSaves.pushedDE)
5212     {
5213       emit2 ("pop de");
5214       _G.calleeSaves.pushedDE = FALSE;
5215     }
5216 
5217   if (_G.calleeSaves.pushedBC)
5218     {
5219       emit2 ("pop bc");
5220       _G.calleeSaves.pushedBC = FALSE;
5221     }
5222 
5223   if (options.profile)
5224     {
5225       emit2 ("!profileexit");
5226     }
5227 
5228   /* if this is an interrupt service routine
5229      then save all potentially used registers. */
5230   if (IFFUNC_ISISR (sym->type))
5231     emit2 ("!popa");
5232   else
5233     {
5234       /* This is a non-ISR function.
5235          If critical function then turn interrupts back on */
5236       if (IFFUNC_ISCRITICAL (sym->type))
5237         {
5238           if (IS_GB || IS_TLCS90)
5239             emit2 ("!ei");
5240           else if (IS_RAB)
5241             emit2 ("ipres");
5242           else
5243             {
5244               symbol *tlbl = newiTempLabel (NULL);
5245               //restore P/O flag
5246               emit2 ("pop af");
5247               //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
5248               //don't enable interrupts as they were off before
5249               emit2 ("jp PO,!tlabel", labelKey2num (tlbl->key));
5250               emit2 ("!ei");
5251               emit2 ("!tlabeldef", labelKey2num (tlbl->key));
5252               genLine.lineCurr->isLabel = 1;
5253             }
5254         }
5255     }
5256 
5257   if (options.debug && currFunc)
5258     {
5259       debugFile->writeEndFunction (currFunc, ic, 1);
5260     }
5261 
5262   if (IFFUNC_ISISR (sym->type))
5263     {
5264       if (is_nmi)
5265         emit2 ("retn");
5266       else if (IS_RAB && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO (sym->type) == INTNO_UNSPEC)
5267         {
5268           emit2 ("ipres");
5269           emit2 ("ret");
5270         }
5271       else if (IS_GB)
5272         emit2 (IFFUNC_ISCRITICAL (sym->type) ? "reti" : "ret");
5273       else
5274         {
5275           if (IFFUNC_ISCRITICAL (sym->type) && !is_nmi)
5276             emit2 ("!ei");
5277           emit2 ("reti");
5278         }
5279     }
5280   else
5281     {
5282       /* Both banked and non-banked just ret */
5283       emit2 ("ret");
5284     }
5285 
5286   _G.flushStatics = 1;
5287   _G.stack.pushed = 0;
5288   _G.stack.offset = 0;
5289 }
5290 
5291 /*-----------------------------------------------------------------*/
5292 /* genRet - generate code for return statement                     */
5293 /*-----------------------------------------------------------------*/
5294 static void
genRet(const iCode * ic)5295 genRet (const iCode *ic)
5296 {
5297   /* Errk.  This is a hack until I can figure out how
5298      to cause dehl to spill on a call */
5299   int size, offset = 0;
5300 
5301   /* if we have no return value then
5302      just generate the "ret" */
5303   if (!IC_LEFT (ic))
5304     goto jumpret;
5305 
5306   /* we have something to return then
5307      move the return value into place */
5308   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
5309   size = AOP_SIZE (IC_LEFT (ic));
5310 
5311   if (size == 2)
5312     {
5313       fetchPairLong (IS_GB ? PAIR_DE : PAIR_HL, AOP (IC_LEFT (ic)), ic, 0);
5314     }
5315   else if (size <= 4)
5316     {
5317       if (IS_GB && size == 4 && requiresHL (AOP (IC_LEFT (ic))))
5318         {
5319           fetchPairLong (PAIR_DE, AOP (IC_LEFT (ic)), 0, 0);
5320           fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, 2);
5321         }
5322       else if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG)
5323         genMove_o (ASMOP_RETURN, 0, IC_LEFT (ic)->aop, 0, IC_LEFT (ic)->aop->size, true, true);
5324       else
5325         {
5326           bool skipbytes[4] = {false, false, false, false}; // Take care to not overwrite hl.
5327           for (offset = 0; offset < size; offset++)
5328             {
5329               if (requiresHL (AOP (IC_LEFT (ic))) && (ASMOP_RETURN->aopu.aop_reg[offset]->rIdx == H_IDX || ASMOP_RETURN->aopu.aop_reg[offset]->rIdx == L_IDX))
5330                 {
5331                   skipbytes[offset] = true;
5332                   continue;
5333                 }
5334               cheapMove (ASMOP_RETURN, offset, IC_LEFT (ic)->aop, offset, true);
5335             }
5336           for (offset = 0; offset < size; offset++)
5337             if (skipbytes[offset] && offset + 1 < size && ASMOP_RETURN->aopu.aop_reg[offset]->rIdx == L_IDX && ASMOP_RETURN->aopu.aop_reg[offset + 1]->rIdx == H_IDX)
5338               {
5339                 fetchPairLong (PAIR_HL, IC_LEFT (ic)->aop, 0, offset);
5340                 break;
5341               }
5342             else if (skipbytes[offset])
5343               {
5344                 cheapMove (ASMOP_RETURN, offset, IC_LEFT (ic)->aop, offset, true);
5345               }
5346         }
5347     }
5348   else if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
5349     {
5350       unsigned long long lit = ullFromVal (AOP (IC_LEFT (ic))->aopu.aop_lit);
5351       setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_GB ? 0 : 2));
5352       emit2 ("ld a, (hl)");
5353       emit2 ("inc hl");
5354       emit2 ("ld h, (hl)");
5355       emit2 ("ld l, a");
5356       regalloc_dry_run_cost += 8;
5357       do
5358         {
5359           emit2 ("ld (hl), !immedbyte", (unsigned long) (lit & 0xff));
5360           regalloc_dry_run_cost += 2;
5361           lit >>= 8;
5362           if (size > 1)
5363             {
5364               emit2 ("inc hl");
5365               regalloc_dry_run_cost++;
5366             }
5367         }
5368       while (--size);
5369     }
5370   else if (!IS_GB && AOP_TYPE (IC_LEFT (ic)) == AOP_STK || AOP_TYPE (IC_LEFT (ic)) == AOP_EXSTK
5371            || AOP_TYPE (IC_LEFT (ic)) == AOP_DIR || AOP_TYPE (IC_LEFT (ic)) == AOP_IY)
5372     {
5373       setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_GB ? 0 : 2));
5374       emit2 ("ld e, (hl)");
5375       emit2 ("inc hl");
5376       emit2 ("ld d, (hl)");
5377       regalloc_dry_run_cost += 7;
5378       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK || AOP_TYPE (IC_LEFT (ic)) == AOP_EXSTK)
5379         {
5380           int sp_offset, fp_offset;
5381           fp_offset =
5382             AOP (IC_LEFT (ic))->aopu.aop_stk + (AOP (IC_LEFT (ic))->aopu.aop_stk >
5383                 0 ? _G.stack.param_offset : 0);
5384           sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
5385           emit2 ("ld hl, #%d", sp_offset);
5386           emit2 ("add hl, sp");
5387           regalloc_dry_run_cost += 4;
5388         }
5389       else
5390         {
5391           emit2 ("ld hl, #%s", AOP (IC_LEFT (ic))->aopu.aop_dir);
5392           regalloc_dry_run_cost += 3;
5393         }
5394       emit2 ("ld bc, #%d", size);
5395       emit2 ("ldir");
5396       regalloc_dry_run_cost += 5;
5397     }
5398   else
5399     {
5400       setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_GB ? 0 : 2));
5401       emit2 ("ld c, (hl)");
5402       emit2 ("inc hl");
5403       emit2 ("ld b, (hl)");
5404       regalloc_dry_run_cost += 7;
5405       spillPair (PAIR_HL);
5406       do
5407         {
5408           cheapMove (ASMOP_A, 0, AOP (IC_LEFT (ic)), offset++, true);
5409           emit2 ("ld (bc), a");
5410           regalloc_dry_run_cost++;
5411           if (size > 1)
5412             {
5413               emit2 ("inc bc");
5414               regalloc_dry_run_cost++;
5415             }
5416         }
5417       while (--size);
5418     }
5419   freeAsmop (IC_LEFT (ic), NULL);
5420 
5421 jumpret:
5422   /* generate a jump to the return label
5423      if the next is not the return statement */
5424   if (!(ic->next && ic->next->op == LABEL && IC_LABEL (ic->next) == returnLabel))
5425     {
5426       if (!regalloc_dry_run)
5427         emit2 ("jp !tlabel", labelKey2num (returnLabel->key));
5428       regalloc_dry_run_cost += 3;
5429     }
5430 }
5431 
5432 /*-----------------------------------------------------------------*/
5433 /* genLabel - generates a label                                    */
5434 /*-----------------------------------------------------------------*/
5435 static void
genLabel(const iCode * ic)5436 genLabel (const iCode * ic)
5437 {
5438   /* special case never generate */
5439   if (IC_LABEL (ic) == entryLabel)
5440     return;
5441 
5442   emitLabelSpill (IC_LABEL (ic));
5443 }
5444 
5445 /*-----------------------------------------------------------------*/
5446 /* genGoto - generates a ljmp                                      */
5447 /*-----------------------------------------------------------------*/
5448 static void
genGoto(const iCode * ic)5449 genGoto (const iCode * ic)
5450 {
5451   emit2 ("jp !tlabel", labelKey2num (IC_LABEL (ic)->key));
5452 }
5453 
5454 /*-----------------------------------------------------------------*/
5455 /* genPlusIncr :- does addition with increment if possible         */
5456 /*-----------------------------------------------------------------*/
5457 static bool
genPlusIncr(const iCode * ic)5458 genPlusIncr (const iCode * ic)
5459 {
5460   unsigned int icount;
5461   unsigned int size = getDataSize (IC_RESULT (ic));
5462   PAIR_ID resultId = getPairId (AOP (IC_RESULT (ic)));
5463 
5464   /* will try to generate an increment */
5465   /* if the right side is not a literal
5466      we cannot */
5467   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
5468     return FALSE;
5469 
5470   icount = (unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5471 
5472   /* If result is a pair */
5473   if (resultId != PAIR_INVALID)
5474     {
5475       bool delayed_move;
5476       if (isLitWord (AOP (IC_LEFT (ic))))
5477         {
5478           fetchLitPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)), icount);
5479           return TRUE;
5480         }
5481       if (isPair (AOP (IC_LEFT (ic))) && resultId == PAIR_HL && icount > 3)
5482         {
5483           if (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL)
5484             {
5485               PAIR_ID freep = getDeadPairId (ic);
5486               if (freep != PAIR_INVALID)
5487                 {
5488                   fetchPair (freep, AOP (IC_RIGHT (ic)));
5489                   emit2 ("add hl, %s", _pairs[freep].name);
5490                   regalloc_dry_run_cost += 1;
5491                   return TRUE;
5492                 }
5493             }
5494           else
5495             {
5496               fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
5497               emit2 ("add hl, %s", getPairName (AOP (IC_LEFT (ic))));
5498               regalloc_dry_run_cost += 1;
5499               return TRUE;
5500             }
5501         }
5502       if (icount > 5)
5503         return FALSE;
5504       /* Inc a pair */
5505       delayed_move = (getPairId (AOP (IC_RESULT (ic))) == PAIR_IY && getPairId (AOP (IC_LEFT (ic))) != PAIR_INVALID
5506                       && isPairDead (getPairId (AOP (IC_LEFT (ic))), ic));
5507       if (!sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5508         {
5509           if (icount > 3)
5510             return FALSE;
5511           if (!delayed_move)
5512             fetchPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)));
5513         }
5514       while (icount--)
5515         {
5516           PAIR_ID pair = delayed_move ? getPairId (AOP (IC_LEFT (ic))) : getPairId (AOP (IC_RESULT (ic)));
5517           emit2 ("inc %s", _pairs[pair].name);
5518           regalloc_dry_run_cost += (pair == PAIR_IY ? 2 : 1);
5519         }
5520       if (delayed_move)
5521         fetchPair (getPairId (AOP (IC_RESULT (ic))), AOP (IC_LEFT (ic)));
5522       return TRUE;
5523     }
5524 
5525   if (!IS_GB && isLitWord (AOP (IC_LEFT (ic))) && size == 2 && isPairDead (PAIR_HL, ic))
5526     {
5527       fetchLitPair (PAIR_HL, AOP (IC_LEFT (ic)), icount);
5528       commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
5529       return TRUE;
5530     }
5531 
5532   if (icount > 4) // Not worth it if the sequence of inc gets too long.
5533     return false;
5534 
5535   if (icount > 1 && size == 1 && aopInReg (IC_LEFT (ic)->aop, 0, A_IDX)) // add a, #n is cheaper than sequence of inc a.
5536     return false;
5537 
5538   if (size == 2 && getPairId (AOP (IC_LEFT (ic))) != PAIR_INVALID && icount <= 3 && isPairDead (getPairId (AOP (IC_LEFT (ic))), ic))
5539     {
5540       PAIR_ID pair = getPairId (AOP (IC_LEFT (ic)));
5541       while (icount--)
5542         emit2 ("inc %s", _pairs[pair].name);
5543       commitPair (AOP (IC_RESULT (ic)), pair, ic, FALSE);
5544       return true;
5545     }
5546 
5547   if (size == 2 && icount <= 2 && isPairDead (PAIR_HL, ic) && !IS_GB &&
5548     (IC_LEFT (ic)->aop->type == AOP_HL || IC_LEFT (ic)->aop->type == AOP_IY))
5549     {
5550       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
5551       while (icount--)
5552         emit2 ("inc hl");
5553       regalloc_dry_run_cost++;
5554       commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
5555       return true;
5556     }
5557 
5558   /* if increment 16 bits in register */
5559   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))) && size > 1 && icount == 1)
5560     {
5561       int offset = 0;
5562       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
5563       while (size--)
5564         {
5565           if (size == 1 && getPairId_o (AOP (IC_RESULT (ic)), offset) != PAIR_INVALID)
5566             {
5567               emit2 ("inc %s", _pairs[getPairId_o (AOP (IC_RESULT (ic)), offset)].name);
5568               size--;
5569               offset += 2;
5570               break;
5571             }
5572           emit3_o (A_INC, AOP (IC_RESULT (ic)), offset++, 0, 0);
5573           if (size)
5574             {
5575               if (!regalloc_dry_run)
5576                 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
5577               regalloc_dry_run_cost += 3;
5578             }
5579         }
5580       if (!regalloc_dry_run)
5581         (AOP_TYPE (IC_LEFT (ic)) == AOP_HL || IS_GB
5582          && AOP_TYPE (IC_LEFT (ic)) == AOP_STK) ? emitLabelSpill (tlbl) : emitLabel (tlbl);
5583       else if (AOP_TYPE (IC_LEFT (ic)) == AOP_HL)
5584         spillCached ();
5585       return TRUE;
5586     }
5587 
5588   /* if the sizes are greater than 1 then we cannot */
5589   if (AOP_SIZE (IC_RESULT (ic)) > 1 || AOP_SIZE (IC_LEFT (ic)) > 1)
5590     return FALSE;
5591 
5592   /* If the result is in a register then we can load then increment.
5593    */
5594   if (AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
5595     {
5596       cheapMove (AOP (IC_RESULT (ic)), LSB, AOP (IC_LEFT (ic)), LSB, true);
5597       while (icount--)
5598         emit3_o (A_INC, AOP (IC_RESULT (ic)), LSB, 0, 0);
5599       return TRUE;
5600     }
5601 
5602   /* we can if the aops of the left & result match or
5603      if they are in registers and the registers are the
5604      same */
5605   if (sameRegs (AOP (IC_LEFT (ic)), AOP (IC_RESULT (ic))))
5606     {
5607       while (icount--)
5608         emit3 (A_INC, AOP (IC_LEFT (ic)), 0);
5609       return TRUE;
5610     }
5611 
5612   return FALSE;
5613 }
5614 
5615 /*-----------------------------------------------------------------*/
5616 /* outBitAcc - output a bit in acc                                 */
5617 /*-----------------------------------------------------------------*/
5618 static void
outBitAcc(operand * result)5619 outBitAcc (operand * result)
5620 {
5621   symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
5622   /* if the result is a bit */
5623   if (AOP_TYPE (result) == AOP_CRY)
5624     {
5625       wassertl (0, "Tried to write A into a bit");
5626     }
5627   else
5628     {
5629       if (!regalloc_dry_run)
5630         {
5631           emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
5632           emit2 ("ld a, !one");
5633           emitLabel (tlbl);
5634         }
5635       regalloc_dry_run_cost += 5;
5636       outAcc (result);
5637     }
5638 }
5639 
5640 static bool
couldDestroyCarry(const asmop * aop)5641 couldDestroyCarry (const asmop *aop)
5642 {
5643   if (aop)
5644     {
5645       if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
5646         {
5647           return TRUE;
5648         }
5649     }
5650   return FALSE;
5651 }
5652 
5653 static void
shiftIntoPair(PAIR_ID id,asmop * aop)5654 shiftIntoPair (PAIR_ID id, asmop *aop)
5655 {
5656   wassertl (!IS_GB, "Not implemented for the GBZ80");
5657 
5658   emitDebug ("; Shift into pair");
5659 
5660   switch (id)
5661     {
5662     case PAIR_HL:
5663       setupPair (PAIR_HL, aop, 0);
5664       break;
5665     case PAIR_DE:
5666       _push (PAIR_DE);
5667       setupPair (PAIR_IY, aop, 0);
5668       emit2 ("push iy");
5669       emit2 ("pop %s", _pairs[id].name);
5670       break;
5671     case PAIR_IY:
5672       setupPair (PAIR_IY, aop, 0);
5673       break;
5674     default:
5675       wassertl (0, "Internal error - hit default case");
5676     }
5677 
5678   aop->type = AOP_PAIRPTR;
5679   aop->aopu.aop_pairId = id;
5680   _G.pairs[id].offset = 0;
5681   _G.pairs[id].last_type = aop->type;
5682 }
5683 
5684 static void
setupToPreserveCarry(asmop * result,asmop * left,asmop * right)5685 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
5686 {
5687   wassert (left && right);
5688 
5689   if (!IS_GB)
5690     {
5691       if (couldDestroyCarry (right) && couldDestroyCarry (result))
5692         {
5693           shiftIntoPair (PAIR_HL, right);
5694           /* check result again, in case right == result */
5695           if (couldDestroyCarry (result))
5696             {
5697               if (couldDestroyCarry (left))
5698                 shiftIntoPair (PAIR_DE, result);
5699               else
5700                 shiftIntoPair (PAIR_IY, result);
5701             }
5702         }
5703       else if (couldDestroyCarry (right))
5704         {
5705           if (getPairId (result) == PAIR_HL)
5706             _G.preserveCarry = TRUE;
5707           else
5708             shiftIntoPair (PAIR_HL, right);
5709         }
5710       else if (couldDestroyCarry (result))
5711         {
5712           shiftIntoPair (PAIR_HL, result);
5713         }
5714     }
5715 }
5716 
5717 /*-----------------------------------------------------------------*/
5718 /* genPlus - generates code for addition                           */
5719 /*-----------------------------------------------------------------*/
5720 static void
genPlus(iCode * ic)5721 genPlus (iCode * ic)
5722 {
5723   int size, i, offset = 0;
5724   signed char cached[2];
5725   bool premoved, started;
5726   asmop *leftop;
5727   asmop *rightop;
5728   symbol *tlbl = 0;
5729 
5730   /* special cases :- */
5731 
5732   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
5733   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
5734   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
5735 
5736   /* Swap the left and right operands if:
5737 
5738      if literal, literal on the right or
5739      if left requires ACC or right is already
5740      in ACC */
5741   if ((AOP_TYPE (IC_LEFT (ic)) == AOP_LIT) || (AOP_NEEDSACC (IC_RIGHT (ic))) || aopInReg (IC_RIGHT (ic)->aop, 0, A_IDX))
5742     {
5743       operand *t = IC_RIGHT (ic);
5744       IC_RIGHT (ic) = IC_LEFT (ic);
5745       IC_LEFT (ic) = t;
5746     }
5747 
5748   leftop = IC_LEFT (ic)->aop;
5749   rightop = IC_RIGHT (ic)->aop;
5750 
5751   /* if both left & right are in bit
5752      space */
5753   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_CRY)
5754     {
5755       /* Cant happen */
5756       wassertl (0, "Tried to add two bits");
5757     }
5758 
5759   /* if left in bit space & right literal */
5760   if (AOP_TYPE (IC_LEFT (ic)) == AOP_CRY && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT)
5761     {
5762       /* Can happen I guess */
5763       wassertl (0, "Tried to add a bit to a literal");
5764     }
5765 
5766   /* if I can do an increment instead
5767      of add then GOOD for ME */
5768   if (genPlusIncr (ic) == TRUE)
5769     goto release;
5770 
5771   size = getDataSize (IC_RESULT (ic));
5772 
5773   /* Special case when left and right are constant */
5774   if (isPair (AOP (IC_RESULT (ic))))
5775     {
5776       char *left = Safe_strdup (aopGetLitWordLong (AOP (IC_LEFT (ic)), 0, FALSE));
5777       const char *right = aopGetLitWordLong (AOP (IC_RIGHT (ic)), 0, FALSE);
5778 
5779       if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT && AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT && left && right)
5780         {
5781           struct dbuf_s dbuf;
5782 
5783           /* It's a pair */
5784           /* PENDING: fix */
5785           dbuf_init (&dbuf, 128);
5786           dbuf_printf (&dbuf, "#(%s + %s)", left, right);
5787           Safe_free (left);
5788           emit2 ("ld %s, %s", getPairName (AOP (IC_RESULT (ic))), dbuf_c_str (&dbuf));
5789           dbuf_destroy (&dbuf);
5790           regalloc_dry_run_cost += (getPairId (AOP (IC_RESULT (ic))) == PAIR_IY ? 4 : 3);
5791           goto release;
5792         }
5793       Safe_free (left);
5794     }
5795 
5796   // eZ80 has lea.
5797   if (IS_EZ80_Z80 && isPair (IC_RESULT (ic)->aop) && getPairId (IC_LEFT (ic)->aop) == PAIR_IY && IC_RIGHT (ic)->aop->type == AOP_LIT)
5798     {
5799        int lit = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
5800        if (lit >= -128 && lit < 128)
5801          {
5802            emit2 ("lea %s, iy, #%d", _pairs[getPairId (IC_RESULT (ic)->aop)].name, lit);
5803            regalloc_dry_run_cost += 3;
5804            spillPair (getPairId (IC_RESULT (ic)->aop));
5805            goto release;
5806          }
5807     }
5808 
5809   if ((isPair (AOP (IC_RIGHT (ic))) || isPair (AOP (IC_LEFT (ic)))) && getPairId (AOP (IC_RESULT (ic))) == PAIR_HL)
5810     {
5811       /* Fetch into HL then do the add */
5812       PAIR_ID left = getPairId (AOP (IC_LEFT (ic)));
5813       PAIR_ID right = getPairId (AOP (IC_RIGHT (ic)));
5814 
5815       spillPair (PAIR_HL);
5816 
5817       if (left == PAIR_HL && right != PAIR_INVALID)
5818         {
5819           emit2 ("add hl, %s", _pairs[right].name);
5820           regalloc_dry_run_cost += 1;
5821           goto release;
5822         }
5823       else if (right == PAIR_HL && left != PAIR_INVALID)
5824         {
5825           emit2 ("add hl, %s", _pairs[left].name);
5826           regalloc_dry_run_cost += 1;
5827           goto release;
5828         }
5829       else if (right != PAIR_INVALID && right != PAIR_HL)
5830         {
5831           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
5832           emit2 ("add hl, %s", getPairName (AOP (IC_RIGHT (ic))));
5833           regalloc_dry_run_cost += 1;
5834           goto release;
5835         }
5836       else if (left != PAIR_INVALID && left != PAIR_HL)
5837         {
5838           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
5839           emit2 ("add hl, %s", getPairName (AOP (IC_LEFT (ic))));
5840           regalloc_dry_run_cost += 1;
5841           goto release;
5842         }
5843       else if (left == PAIR_HL && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)))
5844         {
5845           PAIR_ID pair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
5846           fetchPair (pair, AOP (IC_RIGHT (ic)));
5847           emit2 ("add hl, %s", _pairs[pair].name);
5848           regalloc_dry_run_cost += 1;
5849           goto release;
5850         }
5851       else if (right == PAIR_HL && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)))
5852         {
5853           PAIR_ID pair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
5854           fetchPair (pair, AOP (IC_LEFT (ic)));
5855           emit2 ("add hl, %s", _pairs[pair].name);
5856           regalloc_dry_run_cost += 1;
5857           goto release;
5858         }
5859       else
5860         {
5861           /* Can't do it */
5862         }
5863     }
5864 
5865   // Handle AOP_EXSTK conflict with hl here, since setupToPreserveCarry() would cause problems otherwise.
5866   if (IC_RESULT (ic)->aop->type == AOP_EXSTK && (getPairId (IC_LEFT (ic)->aop) == PAIR_HL || getPairId (IC_RIGHT (ic)->aop) == PAIR_HL) &&
5867     (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) && isPairDead (PAIR_HL, ic))
5868     {
5869       PAIR_ID extrapair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
5870       fetchPair (extrapair, getPairId (IC_LEFT (ic)->aop) == PAIR_HL ? IC_RIGHT (ic)->aop : IC_LEFT (ic)->aop);
5871       emit2 ("add hl, %s", _pairs[extrapair].name);
5872       regalloc_dry_run_cost += 1;
5873       spillPair (PAIR_HL);
5874       commitPair (IC_RESULT (ic)->aop, PAIR_HL, ic, FALSE);
5875       goto release;
5876     }
5877   else if (getPairId (AOP (IC_RESULT (ic))) == PAIR_IY &&
5878     (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL && isPair (AOP (IC_RIGHT (ic))) && getPairId (AOP (IC_RIGHT (ic))) != PAIR_IY || getPairId (AOP (IC_RIGHT (ic))) == PAIR_HL && isPair (AOP (IC_LEFT (ic))) && getPairId (AOP (IC_LEFT (ic))) != PAIR_IY) &&
5879     isPairDead (PAIR_HL, ic))
5880     {
5881       PAIR_ID pair = (getPairId (AOP (IC_LEFT (ic))) == PAIR_HL ? getPairId (AOP (IC_RIGHT (ic))) : getPairId (AOP (IC_LEFT (ic))));
5882       emit2 ("add hl, %s", _pairs[pair].name);
5883       _push (PAIR_HL);
5884       _pop (PAIR_IY);
5885       goto release;
5886     }
5887   else if (getPairId (AOP (IC_RESULT (ic))) == PAIR_IY)
5888     {
5889       bool save_pair = FALSE;
5890       PAIR_ID pair;
5891 
5892       if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_IY || getPairId (AOP (IC_LEFT (ic))) == PAIR_BC
5893           || getPairId (AOP (IC_LEFT (ic))) == PAIR_DE || getPairId (AOP (IC_LEFT (ic))) != PAIR_IY
5894           && (AOP_TYPE (IC_RIGHT (ic)) == AOP_IMMD || AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT))
5895         {
5896           operand *t = IC_RIGHT (ic);
5897           IC_RIGHT (ic) = IC_LEFT (ic);
5898           IC_LEFT (ic) = t;
5899         }
5900       pair = getPairId (AOP (IC_RIGHT (ic)));
5901       if (pair != PAIR_BC && pair != PAIR_DE)
5902         {
5903           if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == C_IDX
5904               && (!bitVectBitValue (ic->rSurv, B_IDX) || !isPairDead (PAIR_DE, ic)))
5905             pair = PAIR_BC;
5906           else if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == E_IDX
5907                    && (!bitVectBitValue (ic->rSurv, D_IDX) || !isPairDead (PAIR_BC, ic)))
5908             pair = PAIR_DE;
5909           else
5910             pair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
5911           if (!isPairDead (pair, ic))
5912             save_pair = TRUE;
5913         }
5914       fetchPair (PAIR_IY, AOP (IC_LEFT (ic)));
5915       if (save_pair)
5916         _push (pair);
5917       fetchPair (pair, AOP (IC_RIGHT (ic)));
5918       emit2 ("add iy, %s", _pairs[pair].name);
5919       spillPair (PAIR_IY);
5920       regalloc_dry_run_cost += 2;
5921       if (save_pair)
5922         _pop (pair);
5923       goto release;
5924     }
5925 
5926   /* gbz80 special case:
5927      ld hl,sp+n trashes C so we can't afford to do it during an
5928      add with stack based variables.  Worst case is:
5929      ld  hl,sp+left
5930      ld  a,(hl)
5931      ld  hl,sp+right
5932      add (hl)
5933      ld  hl,sp+result
5934      ld  (hl),a
5935      ld  hl,sp+left+1
5936      ld  a,(hl)
5937      ld  hl,sp+right+1
5938      adc (hl)
5939      ld  hl,sp+result+1
5940      ld  (hl),a
5941      So you can't afford to load up hl if either left, right, or result
5942      is on the stack (*sigh*)  The alt is:
5943      ld  hl,sp+left
5944      ld  de,(hl)
5945      ld  hl,sp+right
5946      ld  hl,(hl)
5947      add hl,de
5948      ld  hl,sp+result
5949      ld  (hl),hl
5950      Combinations in here are:
5951      * If left or right are in bc then the loss is small - trap later
5952      * If the result is in bc then the loss is also small
5953    */
5954   if (IS_GB)
5955     {
5956       if (AOP_TYPE (IC_LEFT (ic)) == AOP_STK || AOP_TYPE (IC_RIGHT (ic)) == AOP_STK || AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
5957         {
5958           if ((AOP_SIZE (IC_LEFT (ic)) == 2 ||
5959                AOP_SIZE (IC_RIGHT (ic)) == 2) && (AOP_SIZE (IC_LEFT (ic)) <= 2 && AOP_SIZE (IC_RIGHT (ic)) <= 2 || size == 2))
5960             {
5961               if (getPairId (AOP (IC_RIGHT (ic))) == PAIR_BC || getPairId (AOP (IC_RIGHT (ic))) == PAIR_DE)
5962                 {
5963                   /* Swap left and right */
5964                   operand *t = IC_RIGHT (ic);
5965                   IC_RIGHT (ic) = IC_LEFT (ic);
5966                   IC_LEFT (ic) = t;
5967                 }
5968               if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC)
5969                 {
5970                   fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
5971                   emit2 ("add hl, bc");
5972                   regalloc_dry_run_cost += 1;
5973                 }
5974               else
5975                 {
5976                   if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP_SIZE (IC_RIGHT (ic)) == 2 && AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP_SIZE (IC_LEFT (ic)) == 2)
5977                     {
5978                       const short dst[4] = { E_IDX, L_IDX, D_IDX, H_IDX };
5979                       short src[4];
5980                       if (AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == E_IDX
5981                           || AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == L_IDX)
5982                         {
5983                           src[0] = AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx;
5984                           src[1] = AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx;
5985                           src[2] = AOP (IC_RIGHT (ic))->aopu.aop_reg[1]->rIdx;
5986                           src[3] = AOP (IC_LEFT (ic))->aopu.aop_reg[1]->rIdx;
5987                         }
5988                       else
5989                         {
5990                           src[1] = AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx;
5991                           src[0] = AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx;
5992                           src[3] = AOP (IC_RIGHT (ic))->aopu.aop_reg[1]->rIdx;
5993                           src[2] = AOP (IC_LEFT (ic))->aopu.aop_reg[1]->rIdx;
5994                         }
5995                       regMove (dst, src, size, FALSE);
5996                     }
5997                   else if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG &&
5998                            (AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == E_IDX
5999                             || AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == D_IDX || AOP_SIZE (IC_RIGHT (ic)) == 2
6000                             && (AOP (IC_RIGHT (ic))->aopu.aop_reg[1]->rIdx == E_IDX
6001                                 || AOP (IC_RIGHT (ic))->aopu.aop_reg[1]->rIdx == D_IDX)))
6002                     {
6003                       fetchPair (PAIR_DE, AOP (IC_RIGHT (ic)));
6004                       fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6005                     }
6006                   else
6007                     {
6008                       fetchPair (PAIR_DE, AOP (IC_LEFT (ic)));
6009                       fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
6010                     }
6011                   emit2 ("add hl, de");
6012                   regalloc_dry_run_cost += 1;
6013                 }
6014               spillPair (PAIR_HL);
6015               commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
6016               goto release;
6017             }
6018         }
6019       if (size == 4)
6020         {
6021           /* Be paranoid on the GB with 4 byte variables due to how C
6022              can be trashed by lda hl,n(sp).
6023            */
6024           _gbz80_emitAddSubLong (ic, TRUE);
6025           goto release;
6026         }
6027     }
6028 
6029   // Avoid overwriting operand in h or l when setupToPreserveCarry () loads hl - only necessary if carry is actually used during addition.
6030   premoved = FALSE;
6031   if (size > 1 && !(size == 2 && (isPair (leftop) && rightop->type == AOP_LIT)))
6032     {
6033       if (!couldDestroyCarry (leftop) && (couldDestroyCarry (rightop) || couldDestroyCarry (AOP (IC_RESULT (ic)))))
6034         {
6035           cheapMove (ASMOP_A, 0, leftop, offset, true);
6036           premoved = TRUE;
6037         }
6038 
6039       setupToPreserveCarry (AOP (IC_RESULT (ic)), leftop, rightop);
6040     }
6041   // But if we don't actually want to use hl for the addition, it can make sense to setup an op to use cheaper hl instead of iy.
6042   if (size == 1 && !aopInReg(leftop, 0, H_IDX) && !aopInReg(leftop, 0, L_IDX) && isPairDead (PAIR_HL, ic))
6043     {
6044       if (couldDestroyCarry (AOP (IC_RESULT (ic))) &&
6045         (AOP (IC_RESULT (ic)) == leftop || AOP (IC_RESULT (ic)) == rightop))
6046         shiftIntoPair (PAIR_HL, AOP (IC_RESULT (ic)));
6047       else if (couldDestroyCarry (rightop))
6048         shiftIntoPair (PAIR_HL, rightop);
6049     }
6050 
6051   cached[0] = -1;
6052   cached[1] = -1;
6053 
6054   for (i = 0, started = FALSE; i < size;)
6055     {
6056       // Addition of interleaved pairs.
6057       if ((!premoved || i) && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) && leftop->size - i >= 2 && rightop->size - i >= 2)
6058         {
6059           PAIR_ID pair = PAIR_INVALID;
6060 
6061           if (aopInReg (leftop, i, L_IDX) && aopInReg (rightop, i + 1, H_IDX))
6062             {
6063               if (aopInReg (leftop, i + 1, D_IDX) && aopInReg (rightop, i, E_IDX))
6064                 pair = PAIR_DE;
6065               else if (aopInReg (leftop, i + 1, B_IDX) && aopInReg (rightop, i, C_IDX))
6066                 pair = PAIR_BC;
6067             }
6068           else if (aopInReg (leftop, i + 1, H_IDX) && aopInReg (rightop, i, L_IDX))
6069             {
6070               if (aopInReg (leftop, i, E_IDX) && aopInReg (rightop, i + 1, D_IDX))
6071                 pair = PAIR_DE;
6072               else if (aopInReg (leftop, i, C_IDX) && aopInReg (rightop, i + 1, B_IDX))
6073                 pair = PAIR_BC;
6074             }
6075 
6076           if (pair != PAIR_INVALID)
6077             {
6078               if (started)
6079                 {
6080                   emit2 ("adc hl, %s", _pairs[pair].name);
6081                   regalloc_dry_run_cost += 2;
6082                 }
6083               else
6084                 {
6085                   emit2 ("add hl, %s", _pairs[pair].name);
6086                   started = TRUE;
6087                   regalloc_dry_run_cost += 1;
6088                 }
6089               i += 2;
6090               continue;
6091             }
6092         }
6093 
6094       if ((!premoved || i) && !started && i == size - 2 && !i && isPair (AOP (IC_RIGHT (ic))) && AOP_TYPE (IC_LEFT (ic)) == AOP_IMMD && getPairId (AOP (IC_RIGHT (ic))) != PAIR_HL
6095           && isPairDead (PAIR_HL, ic))
6096         {
6097           fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
6098           emit2 ("add hl, %s", getPairName (AOP (IC_RIGHT (ic))));
6099           started = TRUE;
6100           regalloc_dry_run_cost += 1;
6101           spillPair (PAIR_HL);
6102           commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
6103           i += 2;
6104         }
6105      else  if ((!premoved || i) && !started && i == size - 2 && !i && isPair (AOP (IC_LEFT (ic))) && (rightop->type == AOP_LIT  || rightop->type == AOP_IMMD) && getPairId (AOP (IC_LEFT (ic))) != PAIR_HL
6106           && isPairDead (PAIR_HL, ic))
6107         {
6108           fetchPair (PAIR_HL, AOP (IC_RIGHT (ic)));
6109           emit2 ("add hl, %s", getPairName (AOP (IC_LEFT (ic))));
6110           started = TRUE;
6111           regalloc_dry_run_cost += 1;
6112           spillPair (PAIR_HL);
6113           commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
6114           i += 2;
6115         }
6116       else if ((!premoved || i) && !started && i == size - 2 && !i && aopInReg (leftop, i, HL_IDX) && isPair (AOP (IC_RIGHT (ic))) && isPairDead (PAIR_HL, ic))
6117         {
6118           emit2 ("add hl, %s", getPairName (AOP (IC_RIGHT (ic))));
6119           started = TRUE;
6120           regalloc_dry_run_cost += 1;
6121           commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
6122           i += 2;
6123         }
6124       else if ((!premoved || i) && !started && i == size - 2 && !i && isPair (AOP (IC_LEFT (ic))) && aopInReg (rightop, i, HL_IDX) && isPairDead (PAIR_HL, ic))
6125         {
6126           emit2 ("add hl, %s", getPairName (AOP (IC_LEFT (ic))));
6127           started = TRUE;
6128           regalloc_dry_run_cost += 1;
6129           commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
6130           i += 2;
6131         }
6132       else if ((!premoved || i) && !started && i == size - 2 && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) &&
6133           aopInReg (rightop, i, C_IDX) && !bitVectBitValue (ic->rSurv, B_IDX))
6134         {
6135           if (aopInReg (rightop, i + 1, H_IDX) || aopInReg (rightop, i + 1, L_IDX))
6136             {
6137               cheapMove (ASMOP_B, 0, AOP (IC_RIGHT (ic)), i + 1, true);
6138               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, i);
6139             }
6140           else
6141             {
6142               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, i);
6143               cheapMove (ASMOP_B, 0, AOP (IC_RIGHT (ic)), i + 1, true);
6144             }
6145           emit2 ("add hl, bc");
6146           started = TRUE;
6147           regalloc_dry_run_cost += 1;
6148           i += 2;
6149         }
6150       else if (!options.oldralloc && (!premoved || i) && !started && i == size - 2 && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) &&
6151           aopInReg (leftop, i, C_IDX) && !bitVectBitValue (ic->rSurv, B_IDX))
6152         {
6153           if (aopInReg (leftop, i + 1, H_IDX) || aopInReg (leftop, i + 1, L_IDX))
6154             {
6155               cheapMove (ASMOP_B, 0, AOP (IC_LEFT (ic)), i + 1, true);
6156               fetchPairLong (PAIR_HL, AOP (IC_RIGHT (ic)), 0, i);
6157             }
6158           else
6159             {
6160               fetchPairLong (PAIR_HL, AOP (IC_RIGHT (ic)), 0, i);
6161               cheapMove (ASMOP_B, 0, AOP (IC_LEFT (ic)), i + 1, true);
6162             }
6163           emit2 ("add hl, bc");
6164           started = TRUE;
6165           regalloc_dry_run_cost += 1;
6166           i += 2;
6167         }
6168        else if (!options.oldralloc && (!premoved || i) && !started && i == size - 2 && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) &&
6169           aopInReg (rightop, i, E_IDX) && !bitVectBitValue (ic->rSurv, D_IDX))
6170         {
6171           if (aopInReg (rightop, i + 1, H_IDX) || aopInReg (rightop, i + 1, L_IDX))
6172             {
6173               cheapMove (ASMOP_D, 0, AOP (IC_RIGHT (ic)), i + 1, true);
6174               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, i);
6175             }
6176           else
6177             {
6178               fetchPairLong (PAIR_HL, AOP (IC_LEFT (ic)), 0, i);
6179               cheapMove (ASMOP_D, 0, AOP (IC_RIGHT (ic)), i + 1, true);
6180             }
6181           emit2 ("add hl, de");
6182           started = TRUE;
6183           regalloc_dry_run_cost += 1;
6184           i += 2;
6185         }
6186        else if (!options.oldralloc && (!premoved || i) && !started && i == size - 2 && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) &&
6187           aopInReg (leftop, i, E_IDX) && !bitVectBitValue (ic->rSurv, D_IDX))
6188         {
6189           if (aopInReg (leftop, i + 1, H_IDX) || aopInReg (leftop, i + 1, L_IDX))
6190             {
6191               cheapMove (ASMOP_D, 0, AOP (IC_LEFT (ic)), i + 1, true);
6192               fetchPairLong (PAIR_HL, AOP (IC_RIGHT (ic)), 0, i);
6193             }
6194           else
6195             {
6196               fetchPairLong (PAIR_HL, AOP (IC_RIGHT (ic)), 0, i);
6197               cheapMove (ASMOP_D, 0, AOP (IC_LEFT (ic)), i + 1, true);
6198             }
6199           emit2 ("add hl, de");
6200           started = TRUE;
6201           regalloc_dry_run_cost += 1;
6202           i += 2;
6203         }
6204       // When adding a literal, the 16 bit addition results in smaller, faster code than two 8-bit additions.
6205       else if ((!premoved || i) && aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) && aopInReg (leftop, i, HL_IDX) && (rightop->type == AOP_LIT && !aopIsLitVal (rightop, i, 1, 0) || rightop->type == AOP_IMMD))
6206         {
6207           PAIR_ID pair = getFreePairId (ic);
6208           bool pair_alive;
6209           if (pair == PAIR_INVALID)
6210             pair = PAIR_DE;
6211           if (pair_alive = !isPairDead (pair, ic))
6212             _push (pair);
6213           fetchPairLong (pair, AOP (IC_RIGHT (ic)), 0, i);
6214           if (started)
6215             {
6216               emit2 ("adc hl, %s", _pairs[pair].name);
6217               regalloc_dry_run_cost += 2;
6218             }
6219           else
6220             {
6221               emit2 ("add hl, %s", _pairs[pair].name);
6222               started = TRUE;
6223               regalloc_dry_run_cost += 1;
6224             }
6225           regalloc_dry_run_cost += 1;
6226           if (pair_alive)
6227             _pop (pair);
6228           i += 2;
6229         }
6230       // When adding registers the 16 bit addition results in smaller, faster code than an 8-bit addition.
6231       else if ((!premoved || i) && i == size - 1 && isPairDead (PAIR_HL, ic) && aopInReg (AOP (IC_RESULT (ic)), i, L_IDX)
6232         && (aopInReg (leftop, i, L_IDX) || aopInReg (rightop, i, L_IDX))
6233         && (aopInReg (leftop, i, C_IDX) || aopInReg (rightop, i, C_IDX) || aopInReg (leftop, i, E_IDX) || aopInReg (rightop, i, E_IDX)))
6234         {
6235           PAIR_ID pair = (leftop->aopu.aop_reg[i]->rIdx == C_IDX
6236                       || rightop->aopu.aop_reg[i]->rIdx == C_IDX) ? PAIR_BC : PAIR_DE;
6237           if (started)
6238             {
6239               emit2 ("adc hl, %s", _pairs[pair].name);
6240               regalloc_dry_run_cost += 2;
6241             }
6242           else
6243             {
6244               emit2 ("add hl, %s", _pairs[pair].name);
6245               started = TRUE;
6246               regalloc_dry_run_cost += 1;
6247             }
6248           i++;
6249         }
6250       // When adding a literal, the 16 bit addition results in smaller, slower code than an 8-bit addition.
6251       else if ((!premoved || i) && optimize.codeSize && !started && i == size - 1 && isPairDead (PAIR_HL, ic)
6252         && rightop->type == AOP_LIT && aopInReg (AOP (IC_RESULT (ic)), i, L_IDX) && aopInReg (leftop, i, L_IDX)
6253         && (!bitVectBitValue (ic->rSurv, C_IDX) || !bitVectBitValue (ic->rSurv, E_IDX)))
6254         {
6255           PAIR_ID pair = bitVectBitValue (ic->rSurv, C_IDX) ? PAIR_DE : PAIR_BC;
6256           emit2 ("ld %s, !immedbyte", _pairs[pair].l, ((unsigned int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit)) & 0xff);
6257           emit2 ("add hl, %s", _pairs[pair].name);
6258           started = TRUE;
6259           regalloc_dry_run_cost += 3;
6260           i++;
6261         }
6262       // Skip over this byte.
6263       else if (!premoved && !started && (leftop->type == AOP_REG || AOP (IC_RESULT (ic))->type == AOP_REG) && aopIsLitVal (rightop, i, 1, 0))
6264         {
6265           cheapMove (AOP (IC_RESULT (ic)), i, leftop, i, true);
6266           i++;
6267         }
6268       // Conditional 16-bit inc.
6269       else if (i == size - 2 && started && aopIsLitVal (rightop, i, 2, 0) && (
6270         aopInReg (AOP (IC_RESULT (ic)), i, BC_IDX) && aopInReg (leftop, i, BC_IDX) ||
6271         aopInReg (AOP (IC_RESULT (ic)), i, DE_IDX) && aopInReg (leftop, i, DE_IDX) ||
6272         aopInReg (AOP (IC_RESULT (ic)), i, HL_IDX) && aopInReg (leftop, i, HL_IDX) ||
6273         aopInReg (AOP (IC_RESULT (ic)), i, IY_IDX) && aopInReg (leftop, i, IY_IDX)))
6274         {
6275           PAIR_ID pair = getPairId_o (leftop, i);
6276 
6277           if (!tlbl && !regalloc_dry_run)
6278             tlbl = newiTempLabel (0);
6279 
6280           if (!regalloc_dry_run)
6281             emit2 ("jp NC, !tlabel", labelKey2num (tlbl->key));
6282           regalloc_dry_run_cost += 2; // Use cost of jr as the peephole optimizer can typically optimize this jp into jr. Do not emit jr directly to still allow jump-to-jump optimization.
6283           emit2 ("inc %s", _pairs[pair].name);
6284           regalloc_dry_run_cost += (1 + (pair == PAIR_IY));
6285           i += 2;
6286         }
6287       // Conditional 8-bit inc.
6288       else if (i == size - 1 && started && aopIsLitVal (rightop, i, 1, 0) &&
6289         !aopInReg (leftop, i, A_IDX) && // adc a, #0 is cheaper than conditional inc.
6290         (i < leftop->size &&
6291         leftop->type == AOP_REG && AOP (IC_RESULT (ic))->type == AOP_REG &&
6292         leftop->aopu.aop_reg[i]->rIdx == AOP (IC_RESULT (ic))->aopu.aop_reg[i]->rIdx &&
6293         leftop->aopu.aop_reg[i]->rIdx != IYL_IDX && leftop->aopu.aop_reg[i]->rIdx != IYH_IDX ||
6294         leftop->type == AOP_STK && leftop == AOP (IC_RESULT (ic)) ||
6295         leftop->type == AOP_PAIRPTR && leftop->aopu.aop_pairId == PAIR_HL))
6296         {
6297           if (!tlbl && !regalloc_dry_run)
6298             tlbl = newiTempLabel (0);
6299 
6300           if (!regalloc_dry_run)
6301             emit2 ("jp NC, !tlabel", labelKey2num (tlbl->key));
6302           regalloc_dry_run_cost += 2; // Use cost of jr as the peephole optimizer can typically optimize this jp into jr. Do not emit jr directly to still allow jump-to-jump optimization.
6303           emit3_o (A_INC, leftop, i, 0, 0);
6304           i++;
6305         }
6306       else
6307         {
6308           if (!premoved)
6309             cheapMove (ASMOP_A, 0, leftop, i, true);
6310           else
6311             premoved = FALSE;
6312 
6313           // Can't handle overwritten operand in hl.
6314           if (started && (IC_RESULT (ic)->aop->type == AOP_EXSTK ||  IC_RESULT (ic)->aop->type == AOP_PAIRPTR) && requiresHL (IC_RESULT (ic)->aop) &&
6315             (aopInReg (leftop, i, L_IDX) || aopInReg (leftop, i, H_IDX) || aopInReg (rightop, i, L_IDX) || aopInReg (rightop, i, H_IDX)))
6316             {
6317               wassert (regalloc_dry_run);
6318               regalloc_dry_run_cost += 1000;
6319             }
6320 
6321           if (!started && aopIsLitVal (rightop, i, 1, 0))
6322             ; // Skip over this byte.
6323           // We can use inc / dec only for the only, top non-zero byte, since it neither takes into account an existing carry nor does it update the carry.
6324           else if (!started && i == size - 1 && (aopIsLitVal (rightop, i, 1, 1) || aopIsLitVal (rightop, i, 1, 255)))
6325             {
6326               emit3 (aopIsLitVal (rightop, i, 1, 1) ? A_INC : A_DEC, ASMOP_A, 0);
6327               started = TRUE;
6328             }
6329           else
6330             {
6331               emit3_o (started ? A_ADC : A_ADD, ASMOP_A, 0, rightop, i);
6332               started = TRUE;
6333             }
6334 
6335           _G.preserveCarry = (i != size - 1);
6336           if (size &&
6337             (requiresHL (rightop) && rightop->type != AOP_REG || requiresHL (leftop)
6338             && leftop->type != AOP_REG) && AOP_TYPE (IC_RESULT (ic)) == AOP_REG
6339             && (AOP (IC_RESULT (ic))->aopu.aop_reg[i]->rIdx == L_IDX
6340               || AOP (IC_RESULT (ic))->aopu.aop_reg[i]->rIdx == H_IDX))
6341             {
6342               wassert (cached[0] == -1 || cached[1] == -1);
6343               cached[cached[0] == -1 ? 0 : 1] = offset++;
6344               _push (PAIR_AF);
6345             }
6346           else
6347             cheapMove (AOP (IC_RESULT (ic)), i, ASMOP_A, 0, true);
6348           i++;
6349         }
6350     }
6351 
6352   _G.preserveCarry = FALSE;
6353 
6354   if (tlbl)
6355     emitLabel (tlbl);
6356 
6357   for (size = 1; size >= 0; size--)
6358     if (cached[size] != -1)
6359       {
6360         _pop (PAIR_AF);
6361         cheapMove (AOP (IC_RESULT (ic)), cached[size], ASMOP_A, 0, true);
6362       }
6363 
6364 release:
6365   _G.preserveCarry = FALSE;
6366   freeAsmop (IC_LEFT (ic), NULL);
6367   freeAsmop (IC_RIGHT (ic), NULL);
6368   freeAsmop (IC_RESULT (ic), NULL);
6369 }
6370 
6371 /*-----------------------------------------------------------------*/
6372 /* genSubDec :- does subtraction with decrement if possible        */
6373 /*-----------------------------------------------------------------*/
6374 static bool
genMinusDec(const iCode * ic,asmop * result,asmop * left,asmop * right)6375 genMinusDec (const iCode *ic, asmop *result, asmop *left, asmop *right)
6376 {
6377   unsigned int icount;
6378   unsigned int size = getDataSize (IC_RESULT (ic));
6379 
6380   /* will try to generate a decrement */
6381   /* if the right side is not a literal we cannot */
6382   if (right->type != AOP_LIT)
6383     return FALSE;
6384 
6385   /* if the literal value of the right hand side
6386      is greater than 4 then it is not worth it */
6387   if ((icount = (unsigned int) ulFromVal (right->aopu.aop_lit)) > 2)
6388     return FALSE;
6389 
6390   size = getDataSize (IC_RESULT (ic));
6391 
6392   /* if decrement 16 bits in register */
6393   if (sameRegs (left, result) && (size > 1) && isPair (result))
6394     {
6395       while (icount--)
6396         emit2 ("dec %s", getPairName (result));
6397       return TRUE;
6398     }
6399 
6400   /* If result is a pair */
6401   if (isPair (AOP (IC_RESULT (ic))))
6402     {
6403       fetchPair (getPairId (result), left);
6404       while (icount--)
6405         if (!regalloc_dry_run)
6406           emit2 ("dec %s", getPairName (result));
6407       regalloc_dry_run_cost += 1;
6408       return TRUE;
6409     }
6410 
6411   /* if decrement 16 bits in register */
6412   if (sameRegs (left, result) && size == 2 && isPairDead (_getTempPairId (), ic) && !(requiresHL (left) && _getTempPairId () == PAIR_HL))
6413     {
6414       fetchPair (_getTempPairId (), left);
6415 
6416       while (icount--)
6417         if (!regalloc_dry_run)
6418           emit2 ("dec %s", _getTempPairName ());
6419       regalloc_dry_run_cost += 1;
6420 
6421       commitPair (result, _getTempPairId (), ic, FALSE);
6422 
6423       return TRUE;
6424     }
6425 
6426 
6427   /* if the sizes are greater than 1 then we cannot */
6428   if (result->size > 1 || left->size > 1)
6429     return FALSE;
6430 
6431   /* we can if the aops of the left & result match or if they are in
6432      registers and the registers are the same */
6433   if (sameRegs (left, result))
6434     {
6435       while (icount--)
6436         emit3 (A_DEC, result, 0);
6437       return TRUE;
6438     }
6439 
6440   if (result->type == AOP_REG)
6441     {
6442       cheapMove (result, 0, left, 0, true);
6443       while (icount--)
6444         emit3 (A_DEC, result, 0);
6445       return TRUE;
6446     }
6447 
6448   return FALSE;
6449 }
6450 
6451 /*-----------------------------------------------------------------*/
6452 /* genSub - generates code for subtraction                       */
6453 /*-----------------------------------------------------------------*/
6454 static void
genSub(const iCode * ic,asmop * result,asmop * left,asmop * right)6455 genSub (const iCode *ic, asmop *result, asmop *left, asmop *right)
6456 {
6457   int size, offset = 0;
6458   unsigned long long lit = 0L;
6459 
6460   /* special cases :- */
6461   /* if both left & right are in bit space */
6462   if (left->type == AOP_CRY && right->type == AOP_CRY)
6463     {
6464       wassertl (0, "Tried to subtract two bits");
6465       return;
6466     }
6467 
6468   /* if I can do an decrement instead of subtract then GOOD for ME */
6469   if (genMinusDec (ic, result, left, right) == TRUE)
6470     return;
6471 
6472   size = getDataSize (IC_RESULT (ic));
6473 
6474   if (right->type == AOP_LIT)
6475     {
6476       lit = ullFromVal (right->aopu.aop_lit);
6477       lit = -(long long) lit;
6478     }
6479 
6480   /* Same logic as genPlus */
6481   if (IS_GB)
6482     {
6483       if (left->type == AOP_STK || right->type == AOP_STK || AOP_TYPE (IC_RESULT (ic)) == AOP_STK)
6484         {
6485           if ((left->size == 2 ||
6486                right->size == 2) && (left->size <= 2 && right->size <= 2))
6487             {
6488               PAIR_ID leftp = getPairId (left);
6489               PAIR_ID rightp = getPairId (right);
6490 
6491               if (leftp == PAIR_INVALID && rightp == PAIR_INVALID)
6492                 {
6493                   leftp = PAIR_DE;
6494                   rightp = PAIR_HL;
6495                 }
6496               else if (rightp == PAIR_INVALID)
6497                 rightp = PAIR_DE;
6498               else if (leftp == PAIR_INVALID)
6499                 leftp = PAIR_DE;
6500 
6501               fetchPair (leftp, left);
6502               /* Order is important.  Right may be HL */
6503               fetchPair (rightp, right);
6504 
6505               if (!regalloc_dry_run)
6506                 {
6507                   emit2 ("ld a, %s", _pairs[leftp].l);
6508                   emit2 ("sub a, %s", _pairs[rightp].l);
6509                   emit2 ("ld e, a");
6510                   emit2 ("ld a, %s", _pairs[leftp].h);
6511                   emit2 ("sbc a, %s", _pairs[rightp].h);
6512                 }
6513               regalloc_dry_run_cost += 5;
6514 
6515               if (AOP_SIZE (IC_RESULT (ic)) > 1)
6516                 cheapMove (AOP (IC_RESULT (ic)), 1, ASMOP_A, 0, true);
6517               cheapMove (AOP (IC_RESULT (ic)), 0, ASMOP_E, 0, true);
6518               return;
6519             }
6520         }
6521       if (size == 4)
6522         {
6523           /* Be paranoid on the GB with 4 byte variables due to how C
6524              can be trashed by lda hl,n(sp).
6525            */
6526           _gbz80_emitAddSubLongLong (ic, left, right, FALSE);
6527           return;
6528         }
6529     }
6530 
6531   setupToPreserveCarry (result, left, right);
6532 
6533   /* if literal right, add a, #-lit, else normal subb */
6534   while (size)
6535     {
6536       if (!IS_GB &&
6537         aopInReg (result, offset, HL_IDX) &&
6538         (aopInReg (left, offset, HL_IDX) || left->type == AOP_LIT || left->type == AOP_IY) &&
6539         (aopInReg (right, offset, BC_IDX) || aopInReg (right, offset, DE_IDX) || ((right->type == AOP_IY || right->type == AOP_HL) && getFreePairId (ic) != PAIR_INVALID)))
6540         {
6541           PAIR_ID rightpair;
6542 
6543           if (left->type == AOP_LIT || left->type == AOP_IY)
6544             fetchPairLong (PAIR_HL, left, ic, offset);
6545           if (right->type == AOP_IY || right->type == AOP_HL)
6546             {
6547               rightpair = getFreePairId (ic);
6548               fetchPairLong (rightpair, right, ic, offset);
6549             }
6550           else
6551             rightpair = getPartPairId (right, offset);
6552 
6553           if (!offset)
6554             emit3 (A_CP, ASMOP_A, ASMOP_A);
6555           emit2 ("sbc hl, %s", _pairs[rightpair].name);
6556           regalloc_dry_run_cost += 2;
6557           offset += 2;
6558           size -= 2;
6559           _G.preserveCarry = !!size;
6560           continue;
6561         }
6562 
6563       if (right->type != AOP_LIT)
6564         {
6565           if (!offset)
6566             {
6567               if (left->type == AOP_LIT && byteOfVal (left->aopu.aop_lit, offset) == 0x00 && aopInReg (right, offset, A_IDX))
6568                 emit3 (A_NEG, 0, 0);
6569               else
6570                 {
6571                   if (left->type == AOP_LIT && byteOfVal (left->aopu.aop_lit, offset) == 0x00)
6572                     emit3 (A_XOR, ASMOP_A, ASMOP_A);
6573                   else
6574                     cheapMove (ASMOP_A, 0, left, offset, true);
6575                   emit3_o (A_SUB, ASMOP_A, 0, right, offset);
6576                 }
6577             }
6578           else
6579             {
6580               cheapMove (ASMOP_A, 0, left, offset, true);
6581               emit3_o (A_SBC, ASMOP_A, 0, right, offset);
6582             }
6583         }
6584       else
6585         {
6586           cheapMove (ASMOP_A, 0, left, offset, true);
6587 
6588           /* first add without previous c */
6589           if (!offset)
6590             {
6591               if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
6592                 emit3 (A_DEC, ASMOP_A, 0);
6593               else
6594                 {
6595                   if (!regalloc_dry_run)
6596                     emit2 ("add a, !immedbyte", (unsigned int) (lit & 0x0FFL));
6597                   regalloc_dry_run_cost += 2;
6598                 }
6599             }
6600           else
6601             emit2 ("adc a, !immedbyte", (unsigned int) ((lit >> (offset * 8)) & 0x0FFL));
6602         }
6603       size--;
6604       _G.preserveCarry = !!size;
6605       cheapMove (result, offset++, ASMOP_A, 0, true);
6606     }
6607 
6608   if (AOP_SIZE (IC_RESULT (ic)) == 3 && left->size == 3 && !sameRegs (result, left))
6609     {
6610       wassertl (0, "Tried to subtract on a long pointer");
6611     }
6612 }
6613 
6614 /*-----------------------------------------------------------------*/
6615 /* genMinus - generates code for subtraction                       */
6616 /*-----------------------------------------------------------------*/
6617 static void
genMinus(const iCode * ic)6618 genMinus (const iCode *ic)
6619 {
6620   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
6621   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
6622   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
6623 
6624   genSub (ic, AOP (IC_RESULT (ic)), AOP (IC_LEFT (ic)), AOP (IC_RIGHT (ic)));
6625 
6626   _G.preserveCarry = FALSE;
6627   freeAsmop (IC_LEFT (ic), NULL);
6628   freeAsmop (IC_RIGHT (ic), NULL);
6629   freeAsmop (IC_RESULT (ic), NULL);
6630 }
6631 
6632 /*-----------------------------------------------------------------*/
6633 /* genUminusFloat - unary minus for floating points                */
6634 /*-----------------------------------------------------------------*/
6635 static void
genUminusFloat(operand * op,operand * result)6636 genUminusFloat (operand *op, operand *result)
6637 {
6638   emitDebug ("; genUminusFloat");
6639 
6640   /* for this we just need to flip the
6641      first bit then copy the rest in place */
6642 
6643   cheapMove (ASMOP_A, 0, AOP (op), MSB32, true);
6644 
6645   emit2 ("xor a,!immedbyte", 0x80);
6646   regalloc_dry_run_cost += 2;
6647   cheapMove (AOP (result), MSB32, ASMOP_A, 0, true);
6648 
6649   if (operandsEqu (result, op))
6650     return;
6651 
6652   genMove_o (result->aop, 0, op->aop, 0, AOP_SIZE (op) - 1, !aopInReg(result->aop, MSB32, A_IDX), false);
6653 }
6654 
6655 /*-----------------------------------------------------------------*/
6656 /* genUminus - unary minus code generation                         */
6657 /*-----------------------------------------------------------------*/
6658 static void
genUminus(const iCode * ic)6659 genUminus (const iCode *ic)
6660 {
6661   /* assign asmops */
6662   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
6663   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
6664 
6665   /* if both in bit space then special
6666      case */
6667   if (AOP_TYPE (IC_RESULT (ic)) == AOP_CRY && AOP_TYPE (IC_LEFT (ic)) == AOP_CRY)
6668     {
6669       wassertl (0, "Left and right are in bit space");
6670       goto release;
6671     }
6672 
6673   if (IS_FLOAT (operandType (IC_LEFT (ic))))
6674     genUminusFloat (IC_LEFT (ic), IC_RESULT (ic));
6675   else
6676     genSub (ic, AOP (IC_RESULT (ic)), ASMOP_ZERO, AOP (IC_LEFT (ic)));
6677 
6678 release:
6679   _G.preserveCarry = FALSE;
6680   freeAsmop (IC_LEFT (ic), NULL);
6681   freeAsmop (IC_RESULT (ic), NULL);
6682 }
6683 
6684 /*-----------------------------------------------------------------*/
6685 /* genMultOneChar - generates code for unsigned 8x8 multiplication */
6686 /*-----------------------------------------------------------------*/
6687 static void
genMultOneChar(const iCode * ic)6688 genMultOneChar (const iCode * ic)
6689 {
6690   symbol *tlbl1, *tlbl2;
6691   bool savedB = FALSE;
6692 
6693   asmop *result = AOP (IC_RESULT (ic));
6694   int resultsize = AOP_SIZE (IC_RESULT (ic));
6695 
6696   if (IS_GB)
6697     {
6698       wassertl (0, "Multiplication is handled through support function calls on gbz80");
6699       return;
6700     }
6701 
6702   if ((IS_Z180 || IS_EZ80_Z80) && AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
6703     {
6704       if ((resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == B_IDX : !bitVectBitValue (ic->rSurv, B_IDX))
6705           && result->aopu.aop_reg[0]->rIdx == C_IDX)
6706         {
6707           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == C_IDX ||
6708               AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == B_IDX)
6709             {
6710               cheapMove (ASMOP_C, 0, AOP (IC_LEFT (ic)), LSB, true);
6711               cheapMove (ASMOP_B, 0, AOP (IC_RIGHT (ic)), LSB, true);
6712             }
6713           else
6714             {
6715               cheapMove (ASMOP_B, 0, AOP (IC_LEFT (ic)), LSB, true);
6716               cheapMove (ASMOP_C, 0, AOP (IC_RIGHT (ic)), LSB, true);
6717             }
6718           emit2 ("mlt bc");
6719           regalloc_dry_run_cost += 2;
6720           return;
6721         }
6722       if ((resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == D_IDX : !bitVectBitValue (ic->rSurv, D_IDX))
6723           && result->aopu.aop_reg[0]->rIdx == E_IDX)
6724         {
6725           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == E_IDX ||
6726               AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == D_IDX)
6727             {
6728               cheapMove (ASMOP_E, 0, AOP (IC_LEFT (ic)), LSB, true);
6729               cheapMove (ASMOP_D, 0, AOP (IC_RIGHT (ic)), LSB, true);
6730             }
6731           else
6732             {
6733               cheapMove (ASMOP_D, 0, AOP (IC_LEFT (ic)), LSB, true);
6734               cheapMove (ASMOP_E, 0, AOP (IC_RIGHT (ic)), LSB, true);
6735             }
6736           emit2 ("mlt de");
6737           regalloc_dry_run_cost += 2;
6738           return;
6739         }
6740       if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP_TYPE (IC_RIGHT (ic)) == AOP_REG &&
6741           ((AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == H_IDX && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == L_IDX ||
6742             AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == L_IDX && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == H_IDX) &&
6743            (resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == H_IDX : !bitVectBitValue (ic->rSurv, H_IDX))
6744            && result->aopu.aop_reg[0]->rIdx == L_IDX))
6745         {
6746           emit2 ("mlt hl");
6747           regalloc_dry_run_cost += 2;
6748           return;
6749         }
6750     }
6751 
6752   if (IS_RAB && isPairDead (PAIR_HL, ic) && isPairDead (PAIR_BC, ic))
6753     {
6754       const bool save_de = (resultsize > 1 && bitVectBitValue (ic->rSurv, D_IDX) ||
6755         bitVectBitValue (ic->rSurv, E_IDX) && !(AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == E_IDX) && !(AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == E_IDX));
6756       if (save_de)
6757         _push (PAIR_DE);
6758 
6759       if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == E_IDX)
6760          cheapMove (ASMOP_C, 0, AOP (IC_LEFT (ic)), 0, true);
6761       else if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == E_IDX)
6762          cheapMove (ASMOP_C, 0, AOP (IC_RIGHT (ic)), 0, true);
6763       else if (AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == C_IDX)
6764          cheapMove (ASMOP_E, 0, AOP (IC_LEFT (ic)), 0, true);
6765       else if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == C_IDX)
6766          cheapMove (ASMOP_E, 0, AOP (IC_RIGHT (ic)), 0, true);
6767       else
6768         {
6769           cheapMove (ASMOP_C, 0, AOP (IC_LEFT (ic)), 0, true);
6770           cheapMove (ASMOP_E, 0, AOP (IC_RIGHT (ic)), 0, true);
6771         }
6772 
6773       if (resultsize > 1)
6774         {
6775           cheapMove (ASMOP_D, 0, ASMOP_ZERO, 0, true);
6776           cheapMove (ASMOP_B, 0, ASMOP_D, 0, true);
6777         }
6778 
6779       emit2 ("mul");
6780       regalloc_dry_run_cost++;
6781 
6782       if (resultsize > 1)
6783         commitPair (result, PAIR_BC, ic, FALSE);
6784       else
6785         cheapMove (result, 0, ASMOP_C, 0, true);
6786 
6787       if (save_de)
6788         _pop (PAIR_DE);
6789       return;
6790     }
6791 
6792   if (!isPairDead (PAIR_DE, ic))
6793     {
6794       _push (PAIR_DE);
6795       _G.stack.pushedDE = TRUE;
6796     }
6797   if (IS_RAB && !isPairDead (PAIR_BC, ic) ||
6798       !(IS_Z180 || IS_EZ80_Z80) && (!options.oldralloc && bitVectBitValue (ic->rSurv, B_IDX) ||
6799                    options.oldralloc && bitVectBitValue (ic->rMask, B_IDX) && !(getPairId (AOP (IC_RESULT (ic))) == PAIR_BC)))
6800     {
6801       _push (PAIR_BC);
6802       savedB = TRUE;
6803     }
6804 
6805   // genMult() already swapped operands if necessary.
6806   if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == E_IDX ||
6807       AOP_TYPE (IC_RIGHT (ic)) == AOP_REG && AOP (IC_RIGHT (ic))->aopu.aop_reg[0]->rIdx == H_IDX
6808       && !requiresHL (AOP (IC_LEFT (ic))))
6809     {
6810       cheapMove (ASMOP_E, 0, AOP (IC_LEFT (ic)), 0, true);
6811       cheapMove (ASMOP_H, 0, AOP (IC_RIGHT (ic)), 0, true);
6812     }
6813   else
6814     {
6815       cheapMove (ASMOP_E, 0, AOP (IC_RIGHT (ic)), 0, true);
6816       cheapMove (ASMOP_H, 0, AOP (IC_LEFT (ic)), 0, true);
6817     }
6818 
6819   if (IS_Z180 || IS_EZ80_Z80)
6820     {
6821       emit2 ("ld l, e");
6822       emit2 ("mlt hl");
6823       regalloc_dry_run_cost += 3;
6824     }
6825   else if (IS_RAB)
6826     {
6827       emit2 ("ld c, h");
6828       emit2 ("ld d, !immedbyte", 0x00);
6829       emit2 ("ld b, d");
6830       emit2 ("mul");
6831       emit2 ("ld l, c");
6832       emit2 ("ld h, b");
6833       regalloc_dry_run_cost += 7;
6834     }
6835   else if (!regalloc_dry_run)
6836     {
6837       tlbl1 = newiTempLabel (NULL);
6838       tlbl2 = newiTempLabel (NULL);
6839       emit2 ("ld l, !immedbyte", 0x00);
6840       emit2 ("ld d, l");
6841       emit2 ("ld b, !immedbyte", 0x08);
6842       emitLabel (tlbl1);
6843       emit2 ("add hl, hl");
6844       emit2 ("jp NC, !tlabel", labelKey2num (tlbl2->key));
6845       emit2 ("add hl, de");
6846       emitLabel (tlbl2);
6847       emit2 ("djnz !tlabel", labelKey2num (tlbl1->key));
6848       regalloc_dry_run_cost += 12;
6849     }
6850   else
6851     regalloc_dry_run_cost += 12;
6852 
6853 
6854   spillPair (PAIR_HL);
6855 
6856   if (savedB)
6857     {
6858       _pop (PAIR_BC);
6859     }
6860   if (_G.stack.pushedDE)
6861     {
6862       _pop (PAIR_DE);
6863       _G.stack.pushedDE = FALSE;
6864     }
6865 
6866   if (result->type != AOP_HL)
6867     {
6868       if (resultsize == 1)
6869         cheapMove (result, 0, ASMOP_L, 0, true);
6870       else
6871         commitPair (result, PAIR_HL, ic, FALSE);
6872     }
6873   else
6874     {
6875       if (resultsize == 1)
6876         {
6877           emit2 ("ld a, l");
6878           regalloc_dry_run_cost += 1;
6879           cheapMove (result, 0, ASMOP_A, 0, true);
6880         }
6881       else
6882         {
6883           if (!isPairDead (PAIR_DE, ic))
6884             {
6885               _push (PAIR_DE);
6886               _G.stack.pushedDE = TRUE;
6887             }
6888           emit2 ("ld e, l");
6889           emit2 ("ld d, h");
6890           regalloc_dry_run_cost += 2;
6891           commitPair (result, PAIR_DE, ic, FALSE);
6892           if (!isPairDead (PAIR_DE, ic))
6893             {
6894               _pop (PAIR_DE);
6895               _G.stack.pushedDE = FALSE;
6896             }
6897         }
6898     }
6899 }
6900 
6901 /*-----------------------------------------------------------------*/
6902 /* genMult - generates code for multiplication                     */
6903 /*-----------------------------------------------------------------*/
6904 static void
genMult(iCode * ic)6905 genMult (iCode * ic)
6906 {
6907   int val;
6908   int count, i;
6909   /* If true then the final operation should be a subtract */
6910   bool active = FALSE;
6911   bool byteResult;
6912   bool add_in_hl = FALSE;
6913   int a_cost = 0, l_cost = 0;
6914   PAIR_ID pair;
6915 
6916   /* Shouldn't occur - all done through function calls */
6917   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
6918   aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
6919   aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
6920 
6921   byteResult = (AOP_SIZE (IC_RESULT (ic)) == 1);
6922 
6923   if (AOP_SIZE (IC_LEFT (ic)) > 2 || AOP_SIZE (IC_RIGHT (ic)) > 2 || AOP_SIZE (IC_RESULT (ic)) > 2)
6924     wassertl (0, "Large multiplication is handled through support function calls.");
6925 
6926   /* Swap left and right such that right is a literal */
6927   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT)
6928     {
6929       operand *t = IC_RIGHT (ic);
6930       IC_RIGHT (ic) = IC_LEFT (ic);
6931       IC_LEFT (ic) = t;
6932     }
6933 
6934   if (AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT)
6935     {
6936       genMultOneChar (ic);
6937       goto release;
6938     }
6939 
6940   wassertl (AOP_TYPE (IC_RIGHT (ic)) == AOP_LIT, "Right must be a literal.");
6941 
6942   val = (int) ulFromVal (AOP (IC_RIGHT (ic))->aopu.aop_lit);
6943   wassertl (val != 1, "Can't multiply by 1");
6944 
6945   // Try to use mlt.
6946   if ((IS_Z180 || IS_EZ80_Z80) && AOP_SIZE (IC_LEFT (ic)) == 1 && AOP_SIZE (IC_RIGHT (ic)) == 1 &&
6947     (byteResult || SPEC_USIGN (getSpec (operandType (IC_LEFT (ic)))) && SPEC_USIGN (getSpec (operandType (IC_RIGHT (ic))))))
6948     {
6949       pair = getPairId (AOP (IC_RESULT (ic)));
6950       if (pair == PAIR_INVALID && AOP_TYPE (IC_RESULT (ic)) == AOP_REG)
6951         {
6952           if (!bitVectBitValue (ic->rSurv, H_IDX) && AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == L_IDX)
6953             pair = PAIR_HL;
6954           else if (!bitVectBitValue (ic->rSurv, D_IDX) && AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == E_IDX)
6955             pair = PAIR_HL;
6956           else if (!bitVectBitValue (ic->rSurv, B_IDX) && AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == C_IDX)
6957             pair = PAIR_HL;
6958         }
6959       else if (pair == PAIR_INVALID)
6960         pair = getDeadPairId (ic);
6961 
6962       if (pair == PAIR_INVALID)
6963         {
6964           if (!(AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
6965             (AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == L_IDX || AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == H_IDX ||
6966             !byteResult && (AOP (IC_RESULT (ic))->aopu.aop_reg[1]->rIdx == L_IDX || AOP (IC_RESULT (ic))->aopu.aop_reg[1]->rIdx == H_IDX))))
6967             pair = PAIR_HL;
6968           else if (!(AOP_TYPE (IC_RESULT (ic)) == AOP_REG &&
6969             (AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == E_IDX || AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == D_IDX ||
6970             !byteResult && (AOP (IC_RESULT (ic))->aopu.aop_reg[1]->rIdx == E_IDX || AOP (IC_RESULT (ic))->aopu.aop_reg[1]->rIdx == D_IDX))))
6971             pair = PAIR_DE;
6972           else
6973             pair = PAIR_BC;
6974         }
6975 
6976       // For small operands under low register pressure, the standard approach is better than the mlt one.
6977       if (byteResult && val <= 6 && isPairDead (PAIR_HL, ic) && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) &&
6978         !(AOP_TYPE (IC_RESULT (ic)) == AOP_REG && (AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == E_IDX || AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx == C_IDX)))
6979         goto no_mlt;
6980 
6981       if (!isPairDead (pair, ic))
6982         _push (pair);
6983 
6984       switch (pair)
6985         {
6986         case PAIR_HL:
6987           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == H_IDX)
6988             cheapMove (ASMOP_L, 0, AOP (IC_RIGHT (ic)), 0, true);
6989           else
6990             {
6991               cheapMove (ASMOP_L, 0, AOP (IC_LEFT (ic)), 0, true);
6992               cheapMove (ASMOP_H, 0, AOP (IC_RIGHT (ic)), 0, true);
6993             }
6994           break;
6995         case PAIR_DE:
6996           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == D_IDX)
6997             cheapMove (ASMOP_E, 0, AOP (IC_RIGHT (ic)), 0, true);
6998           else
6999             {
7000               cheapMove (ASMOP_E, 0, AOP (IC_LEFT (ic)), 0, true);
7001               cheapMove (ASMOP_D, 0, AOP (IC_RIGHT (ic)), 0, true);
7002             }
7003           break;
7004         default:
7005           wassert (pair == PAIR_BC);
7006           if (AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == B_IDX)
7007             cheapMove (ASMOP_C, 0, AOP (IC_RIGHT (ic)), 0, true);
7008           else
7009             {
7010               cheapMove (ASMOP_C, 0, AOP (IC_LEFT (ic)), 0, true);
7011               cheapMove (ASMOP_B, 0, AOP (IC_RIGHT (ic)), 0, true);
7012             }
7013           break;
7014         }
7015 
7016       emit2 ("mlt %s", _pairs[pair].name);
7017       regalloc_dry_run_cost += 2;
7018 
7019       if (byteResult)
7020         cheapMove (AOP (IC_RESULT (ic)), 0, pair == PAIR_HL ? ASMOP_L : (pair == PAIR_DE ? ASMOP_E : ASMOP_C), 0, true);
7021       else
7022         commitPair (AOP (IC_RESULT (ic)), pair, ic, FALSE);
7023 
7024       if (!isPairDead (pair, ic))
7025         _pop (pair);
7026 
7027       goto release;
7028     }
7029 no_mlt:
7030 
7031   pair = PAIR_DE;
7032   if (getPairId (AOP (IC_LEFT (ic))) == PAIR_BC ||
7033     (byteResult || !bitVectBitValue (ic->rSurv, B_IDX)) && AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == C_IDX)
7034     pair = PAIR_BC;
7035   if (isPairDead (PAIR_BC, ic) && !(AOP_TYPE (IC_LEFT (ic)) == AOP_REG && AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx == E_IDX))
7036     pair = PAIR_BC;
7037 
7038   if (pair == PAIR_DE && (byteResult ? bitVectBitValue (ic->rSurv, E_IDX) : !isPairDead (PAIR_DE, ic)))
7039     {
7040       _push (PAIR_DE);
7041       _G.stack.pushedDE = TRUE;
7042     }
7043 
7044   /* Use 16-bit additions even for 8-bit result when the operands are in the right places. */
7045   if (byteResult)
7046     {
7047       if (!aopInReg (IC_LEFT (ic)->aop, 0, A_IDX))
7048         a_cost += ld_cost (ASMOP_A, AOP (IC_LEFT (ic)));
7049       if (!aopInReg (IC_RESULT (ic)->aop, 0, A_IDX))
7050         a_cost += ld_cost (AOP (IC_RESULT (ic)), ASMOP_A);
7051       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG || AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx != L_IDX)
7052         l_cost += ld_cost (ASMOP_L, AOP (IC_LEFT (ic)));
7053       if (AOP_TYPE (IC_RESULT (ic)) != AOP_REG || AOP (IC_RESULT (ic))->aopu.aop_reg[0]->rIdx != L_IDX)
7054         l_cost += ld_cost (AOP (IC_RESULT (ic)), ASMOP_L);
7055     }
7056   add_in_hl = (!byteResult || isPairDead (PAIR_HL, ic) && l_cost < a_cost);
7057 
7058   if (byteResult)
7059     {
7060       cheapMove (add_in_hl ? ASMOP_L : ASMOP_A, 0, AOP (IC_LEFT (ic)), 0, true);
7061       if (AOP_TYPE (IC_LEFT (ic)) != AOP_REG || AOP (IC_LEFT (ic))->aopu.aop_reg[0]->rIdx != (pair == PAIR_BC ? C_IDX : E_IDX))
7062         cheapMove (pair == PAIR_BC ? ASMOP_C : ASMOP_E, 0, add_in_hl ? ASMOP_L : ASMOP_A, 0, true);
7063     }
7064   else if (AOP_SIZE (IC_LEFT (ic)) == 1 && !SPEC_USIGN (getSpec (operandType (IC_LEFT (ic)))))
7065     {
7066       cheapMove (pair == PAIR_BC ? ASMOP_C : ASMOP_E, 0, AOP (IC_LEFT (ic)), 0, true);
7067       emit2 ("ld a, %s", _pairs[pair].l);
7068       emit2 ("rlc a");
7069       emit2 ("sbc a, a");
7070       emit2 ("ld %s, a", _pairs[pair].h);
7071       regalloc_dry_run_cost += 5;
7072       emit2 ("ld l, %s", _pairs[pair].l);
7073       emit2 ("ld h, %s", _pairs[pair].h);
7074       regalloc_dry_run_cost += 2;
7075     }
7076   else
7077     {
7078       fetchPair (pair, AOP (IC_LEFT (ic)));
7079       if (getPairId (AOP (IC_LEFT (ic))) != PAIR_HL)
7080         {
7081           emit2 ("ld l, %s", _pairs[pair].l);
7082           emit2 ("ld h, %s", _pairs[pair].h);
7083           regalloc_dry_run_cost += 2;
7084         }
7085     }
7086 
7087   i = val;
7088 
7089   for (count = 0; count < 16; count++)
7090     {
7091       if (count != 0 && active)
7092         {
7093           if (!add_in_hl)
7094             emit2 ("add a, a");
7095           else
7096             emit2 ("add hl, hl");
7097           regalloc_dry_run_cost += 1;
7098         }
7099       if (i & 0x8000U)
7100         {
7101           if (active)
7102             {
7103               if (!add_in_hl)
7104                 emit2 ("add a, %s", _pairs[pair].l);
7105               else
7106                 emit2 ("add hl, %s", _pairs[pair].name);
7107               regalloc_dry_run_cost += 1;
7108             }
7109           active = TRUE;
7110         }
7111       i <<= 1;
7112     }
7113 
7114   spillPair (PAIR_HL);
7115 
7116   if (_G.stack.pushedDE)
7117     {
7118       _pop (PAIR_DE);
7119       _G.stack.pushedDE = FALSE;
7120     }
7121 
7122   if (byteResult)
7123     cheapMove (AOP (IC_RESULT (ic)), 0, add_in_hl ? ASMOP_L : ASMOP_A, 0, true);
7124   else
7125     commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, FALSE);
7126 
7127 release:
7128   freeAsmop (IC_LEFT (ic), NULL);
7129   freeAsmop (IC_RIGHT (ic), NULL);
7130   freeAsmop (IC_RESULT (ic), NULL);
7131 }
7132 
7133 /*-----------------------------------------------------------------*/
7134 /* genDiv - generates code for division                            */
7135 /*-----------------------------------------------------------------*/
7136 static void
genDiv(const iCode * ic)7137 genDiv (const iCode * ic)
7138 {
7139   /* Shouldn't occur - all done through function calls */
7140   wassertl (0, "Division is handled through support function calls");
7141 }
7142 
7143 /*-----------------------------------------------------------------*/
7144 /* genMod - generates code for division                            */
7145 /*-----------------------------------------------------------------*/
7146 static void
genMod(const iCode * ic)7147 genMod (const iCode * ic)
7148 {
7149   /* Shouldn't occur - all done through function calls */
7150   wassert (0);
7151 }
7152 
7153 /*-----------------------------------------------------------------*/
7154 /* genIfxJump :- will create a jump depending on the ifx           */
7155 /*-----------------------------------------------------------------*/
7156 static void
genIfxJump(iCode * ic,char * jval)7157 genIfxJump (iCode * ic, char *jval)
7158 {
7159   symbol *jlbl;
7160   const char *inst;
7161 
7162   /* if true label then we jump if condition
7163      supplied is true */
7164   if (IC_TRUE (ic))
7165     {
7166       jlbl = IC_TRUE (ic);
7167       if (!strcmp (jval, "a"))
7168         {
7169           emit3 (A_OR, ASMOP_A, ASMOP_A);
7170           inst = "NZ";
7171         }
7172       else if (!strcmp (jval, "z"))
7173         {
7174           inst = "Z";
7175         }
7176       else if (!strcmp (jval, "nz"))
7177         {
7178           inst = "NZ";
7179         }
7180       else if (!strcmp (jval, "c"))
7181         {
7182           inst = "C";
7183         }
7184       else if (!strcmp (jval, "nc"))
7185         {
7186           inst = "NC";
7187         }
7188       else if (!strcmp (jval, "m"))
7189         {
7190           inst = "M";
7191         }
7192       else if (!strcmp (jval, "p"))
7193         {
7194           inst = "P";
7195         }
7196       else if (!strcmp (jval, "po"))
7197         {
7198           inst = "PO";
7199         }
7200       else if (!strcmp (jval, "pe"))
7201         {
7202           inst = "PE";
7203         }
7204       else
7205         {
7206           /* The buffer contains the bit on A that we should test */
7207           emit2 ("bit %s, a", jval);
7208           regalloc_dry_run_cost += 2;
7209           inst = "NZ";
7210         }
7211     }
7212   else
7213     {
7214       /* false label is present */
7215       jlbl = IC_FALSE (ic);
7216       if (!strcmp (jval, "a"))
7217         {
7218           emit3 (A_OR, ASMOP_A, ASMOP_A);
7219           inst = "Z";
7220         }
7221       else if (!strcmp (jval, "z"))
7222         {
7223           inst = "NZ";
7224         }
7225       else if (!strcmp (jval, "nz"))
7226         {
7227           inst = "Z";
7228         }
7229       else if (!strcmp (jval, "c"))
7230         {
7231           inst = "NC";
7232         }
7233       else if (!strcmp (jval, "nc"))
7234         {
7235           inst = "C";
7236         }
7237       else if (!strcmp (jval, "m"))
7238         {
7239           inst = "P";
7240         }
7241       else if (!strcmp (jval, "p"))
7242         {
7243           inst = "M";
7244         }
7245       else if (!strcmp (jval, "po"))
7246         {
7247           inst = "PE";
7248         }
7249       else if (!strcmp (jval, "pe"))
7250         {
7251           inst = "PO";
7252         }
7253       else
7254         {
7255           /* The buffer contains the bit on A that we should test */
7256           emit2 ("bit %s, a", jval);
7257           regalloc_dry_run_cost += 2;
7258           inst = "Z";
7259         }
7260     }
7261   /* Z80 can do a conditional long jump */
7262   if (!regalloc_dry_run)
7263     emit2 ("jp %s, !tlabel", inst, labelKey2num (jlbl->key));
7264   regalloc_dry_run_cost += 3;
7265 
7266   /* mark the icode as generated */
7267   if (!regalloc_dry_run)
7268     ic->generated = 1;
7269 }
7270 
7271 #if DISABLED
7272 static const char *
_getPairIdName(PAIR_ID id)7273 _getPairIdName (PAIR_ID id)
7274 {
7275   return _pairs[id].name;
7276 }
7277 #endif
7278 
7279 /** Generic compare for > or <
7280  */
7281 static void
genCmp(operand * left,operand * right,operand * result,iCode * ifx,int sign,const iCode * ic)7282 genCmp (operand * left, operand * right, operand * result, iCode * ifx, int sign, const iCode * ic)
7283 {
7284   int size, offset = 0;
7285   unsigned long long lit = 0ull;
7286   bool result_in_carry = FALSE;
7287   int a_always_byte = -1;
7288 
7289   /* if left & right are bit variables */
7290   if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
7291     {
7292       /* Can't happen on the Z80 */
7293       wassertl (0, "Tried to compare two bits");
7294     }
7295   else
7296     {
7297       /* Do a long subtract of right from left. */
7298       size = max (AOP_SIZE (left), AOP_SIZE (right));
7299 
7300       if (AOP_TYPE (right) == AOP_SFR)  /* Avoid overwriting A */
7301         {
7302           bool save_a, save_b, save_bc;
7303           wassertl (size == 1, "Right side sfr in comparison with more than 8 bits.");
7304 
7305           save_b = bitVectBitValue (ic->rSurv, B_IDX);
7306           save_bc = (save_b && bitVectBitValue (ic->rSurv, C_IDX));
7307           save_a = (aopInReg (left->aop, 0, A_IDX) ||
7308                     aopInReg (left->aop, 0, B_IDX) && save_b ||
7309                     aopInReg (left->aop, 0, C_IDX) && !save_b && save_bc);
7310 
7311           if (save_bc)
7312             _push (PAIR_BC);
7313           if (save_a)
7314             {
7315               cheapMove (ASMOP_A, 0, AOP (right), 0, true);
7316               _push (PAIR_AF);
7317             }
7318           else
7319             cheapMove (ASMOP_A, 0, AOP (right), 0, true);
7320           cheapMove (save_b ? ASMOP_C : ASMOP_B, 0, ASMOP_A, 0, true);
7321           if (save_a)
7322             _pop (PAIR_AF);
7323           else
7324             cheapMove (ASMOP_A, 0, AOP (left), 0, true);
7325           emit3_o (A_SUB, ASMOP_A, 0, save_b ? ASMOP_C : ASMOP_B, offset);
7326           if (save_bc)
7327             _pop (PAIR_BC);
7328           result_in_carry = TRUE;
7329           goto fix;
7330         }
7331 
7332       // Preserve A if necessary
7333       if (ifx && size == 1 && !sign && aopInReg (left->aop, 0, A_IDX) && bitVectBitValue (ic->rSurv, A_IDX) &&
7334         (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (right) == AOP_REG && AOP (right)->aopu.aop_reg[offset]->rIdx != IYL_IDX && AOP (right)->aopu.aop_reg[offset]->rIdx != IYH_IDX || AOP_TYPE (right) == AOP_STK))
7335         {
7336           emit3 (A_CP, ASMOP_A, AOP (right));
7337           result_in_carry = TRUE;
7338           goto release;
7339         }
7340 
7341       // On the Gameboy we can't afford to adjust HL as it may trash the carry.
7342       if (size > 1 && (IS_GB || IY_RESERVED) && left->aop->type != AOP_REG && right->aop->type != AOP_REG && (requiresHL (AOP (right)) && requiresHL (AOP (left))))
7343         {
7344           if (!isPairDead (PAIR_DE, ic))
7345             _push (PAIR_DE);
7346 
7347           pointPairToAop (PAIR_DE, left->aop, 0);
7348           pointPairToAop (PAIR_HL, right->aop, 0);
7349 
7350           while (size--)
7351             {
7352               emit2 ("ld a, (de)");
7353               emit2 ("%s a, (hl)", offset == 0 ? "sub" : "sbc");
7354               regalloc_dry_run_cost += 2;
7355 
7356               if (size != 0)
7357                 {
7358                   emit2 ("inc hl");
7359                   emit2 ("inc de");
7360                   regalloc_dry_run_cost += 2;
7361                 }
7362               offset++;
7363             }
7364           if (sign && IS_GB)
7365             {
7366               wassert(isPairDead (PAIR_DE, ic));
7367               emit2 ("ld a, (de)");
7368               emit2 ("ld d, a");
7369               emit2 ("ld e, (hl)");
7370               regalloc_dry_run_cost += 3;
7371             }
7372 
7373           spillPair (PAIR_DE);
7374           if (!isPairDead (PAIR_DE, ic))
7375             _pop (PAIR_DE);
7376 
7377           spillPair (PAIR_HL);
7378           result_in_carry = TRUE;
7379           goto fix;
7380         }
7381       else if (size > 1 && IS_GB && (requiresHL (AOP (right)) && !requiresHL (AOP (left))))
7382         {
7383           if (!regalloc_dry_run)
7384             aopGet (AOP (right), LSB, FALSE);
7385 
7386           while (size--)
7387             {
7388               cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7389               emit2 ("%s a, (hl)", offset == 0 ? "sub" : "sbc");
7390               regalloc_dry_run_cost += 1;
7391 
7392               if (size != 0)
7393                 {
7394                   emit2 ("inc hl");
7395                   regalloc_dry_run_cost += 1;
7396                 }
7397               offset++;
7398             }
7399           if (sign)
7400             {
7401               cheapMove (ASMOP_A, 0, AOP (left), offset - 1, true);
7402               emit2 ("ld d, a");
7403               emit2 ("ld e, (hl)");
7404               regalloc_dry_run_cost += 2;
7405             }
7406           spillPair (PAIR_HL);
7407           result_in_carry = TRUE;
7408           goto fix;
7409         }
7410       else if (size > 1 && IS_GB && (!requiresHL (AOP (right)) && requiresHL (AOP (left))))
7411         {
7412           if (!regalloc_dry_run)
7413             aopGet (AOP (left), LSB, FALSE);
7414 
7415           while (size--)
7416             {
7417               emit2 ("ld a, (hl)");
7418               regalloc_dry_run_cost += 1;
7419               emit3_o (offset == 0 ? A_SUB : A_SBC, ASMOP_A, 0, AOP (right), offset);
7420 
7421               if (size != 0)
7422                 {
7423                   emit2 ("inc hl");
7424                   regalloc_dry_run_cost += 1;
7425                 }
7426               offset++;
7427             }
7428           if (sign)
7429             {
7430               emit2 ("ld d, (hl)");
7431               regalloc_dry_run_cost += 1;
7432               cheapMove (ASMOP_A, 0, AOP (right), offset - 1, true);
7433               emit2 ("ld e, a");
7434               regalloc_dry_run_cost += 1;
7435             }
7436           spillPair (PAIR_HL);
7437           result_in_carry = TRUE;
7438           goto fix;
7439         }
7440 
7441       if (IS_GB && sign && AOP_TYPE (right) != AOP_LIT)
7442         {
7443           cheapMove (ASMOP_A, 0, AOP (right), size - 1, true);
7444           cheapMove (ASMOP_E, 0, ASMOP_A, 0, true);
7445           cheapMove (ASMOP_A, 0, AOP (left), size - 1, true);
7446           cheapMove (ASMOP_D, 0, ASMOP_A, 0, true);
7447         }
7448 
7449       if (AOP_TYPE (right) == AOP_LIT)
7450         {
7451           lit = ullFromVal (AOP (right)->aopu.aop_lit);
7452 
7453           /* optimize if(x < 0) or if(x >= 0) */
7454           if (lit == 0ull)
7455             {
7456               if (!sign)
7457                 {
7458                   /* No sign so it's always false */
7459                   emit3 (A_CP, ASMOP_A, ASMOP_A);
7460                   result_in_carry = TRUE;
7461                 }
7462               else
7463                 {
7464                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx &&
7465                     (AOP_TYPE (left) == AOP_REG || AOP_TYPE (left) == AOP_STK && !IS_GB))
7466                     {
7467                       if (!regalloc_dry_run)
7468                         emit2 ("bit 7, %s", aopGet (AOP (left), AOP_SIZE (left) - 1, FALSE));
7469                       regalloc_dry_run_cost += ((AOP_TYPE (left) == AOP_REG) ? 2 : 4);
7470                       genIfxJump (ifx, "nz");
7471                       return;
7472                     }
7473                   /* Just load in the top most bit */
7474                   cheapMove (ASMOP_A, 0, AOP (left), AOP_SIZE (left) - 1, true);
7475                   if (!(AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result)) && ifx)
7476                     {
7477                       genIfxJump (ifx, "7");
7478                       return;
7479                     }
7480                   else
7481                     {
7482                       if (ifx)
7483                         {
7484                           genIfxJump (ifx, "nc");
7485                           return;
7486                         }
7487                       result_in_carry = FALSE;
7488                     }
7489                 }
7490               goto release;
7491             }
7492 
7493           while (!((lit >> (offset * 8)) & 0xffull))
7494             {
7495               size--;
7496               offset++;
7497             }
7498 
7499           if (sign)             /* Map signed operands to unsigned ones. This pre-subtraction workaround to lack of signed comparison is cheaper than the post-subtraction one at fix. */
7500             {
7501               if (size == 2 && !(IS_GB || !ifx && requiresHL(AOP(result)) && AOP_TYPE (result) != AOP_REG) && isPairDead (PAIR_HL, ic) && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) && (getPairId (AOP (left)) == PAIR_HL || IS_RAB && (AOP_TYPE (left) == AOP_STK || AOP_TYPE (left) == AOP_EXSTK)))
7502                 {
7503                   PAIR_ID litpair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
7504                   fetchPair (PAIR_HL, AOP (left));
7505                   emit2 ("ld %s, !immedbyte", _pairs[litpair].name, (unsigned long) ((lit ^ 0x8000u) & 0xffffu));
7506                   regalloc_dry_run_cost += 3;
7507                   emit2 ("add hl, hl");
7508                   emit2 ("ccf");
7509                   regalloc_dry_run_cost += 2;
7510                   if (IS_RAB)
7511                     {
7512                       emit2 ("rr hl");
7513                       regalloc_dry_run_cost += 1;
7514                     }
7515                   else
7516                     {
7517                       emit2 ("rr h");
7518                       emit2 ("rr l");
7519                       regalloc_dry_run_cost += 2;
7520                     }
7521                   emit2 ("sbc hl, %s", _pairs[litpair].name);
7522                   regalloc_dry_run_cost += 2;
7523                   result_in_carry = TRUE;
7524                   goto release;
7525                 }
7526 
7527               cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7528               if (size == 1)
7529                 {
7530                   emit2 ("xor a, !immedbyte", 0x80);
7531                   regalloc_dry_run_cost += 2;
7532                 }
7533               emit2 ("sub a, !immedbyte", (unsigned long) (((lit >> (offset * 8)) & 0xff) ^ (size == 1 ? 0x80 : 0x00)));
7534               regalloc_dry_run_cost += 2;
7535               size--;
7536               offset++;
7537 
7538               while (size--)
7539                 {
7540                   cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7541                   if (!size)
7542                     {
7543                       emit2 ("rla");
7544                       emit2 ("ccf");
7545                       emit2 ("rra");
7546                       regalloc_dry_run_cost += 3;
7547                     }
7548                   /* Subtract through, propagating the carry */
7549                   emit2 ("sbc a, !immedbyte", (unsigned long) (((lit >> (offset++ * 8)) & 0xff) ^ (size ? 0x00 : 0x80)));
7550                   regalloc_dry_run_cost += 2;
7551                 }
7552               result_in_carry = TRUE;
7553               goto release;
7554             }
7555         }
7556       if (!IS_GB && (!sign || size > 2) && (getPartPairId (left->aop, offset) == PAIR_HL || size == 2 && left->aop->type == AOP_IY) && isPairDead (PAIR_HL, ic) &&
7557         (getPartPairId (right->aop, offset) == PAIR_DE || getPartPairId (right->aop, offset) == PAIR_BC))
7558         {
7559           if (left->aop->type == AOP_DIR || left->aop->type == AOP_IY)
7560             fetchPair (PAIR_HL, left->aop);
7561           emit3 (A_XOR, ASMOP_A, ASMOP_A); // Clear carry.
7562           emit2 ("sbc hl, %s", _pairs[getPartPairId (AOP (right), offset)].name);
7563           regalloc_dry_run_cost += 2;
7564           size -= 2;
7565           offset += 2;
7566         }
7567       else
7568         {
7569           if (AOP_TYPE (left) == AOP_LIT && byteOfVal (AOP (left)->aopu.aop_lit, offset) == 0x00)
7570             emit3 (A_XOR, ASMOP_A, ASMOP_A);
7571           else
7572             cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7573           if (size > 1 && AOP_TYPE (left) == AOP_LIT)
7574             {
7575               emit3_o (A_CP, ASMOP_A, 0, AOP (right), offset);
7576               a_always_byte = byteOfVal (AOP (left)->aopu.aop_lit, offset);
7577             }
7578           else
7579             emit3_o (A_SUB, ASMOP_A, 0, AOP (right), offset);
7580           size--;
7581           offset++;
7582         }
7583 
7584       /* Subtract through, propagating the carry */
7585       while (size)
7586         {
7587           if (!IS_GB && (!sign || size > 2) &&
7588             isPairDead (PAIR_HL, ic) &&
7589             (getPartPairId (left->aop, offset) == PAIR_HL || left->aop->type == AOP_LIT && right->aop->regs[L_IDX] < offset && right->aop->regs[H_IDX] < offset) &&
7590             (getPartPairId (right->aop, offset) == PAIR_DE || getPartPairId (right->aop, offset) == PAIR_BC))
7591             {
7592               fetchPairLong (PAIR_HL, left->aop, 0, offset);
7593               emit2 ("sbc hl, %s", _pairs[getPartPairId (AOP (right), offset)].name);
7594               regalloc_dry_run_cost += 2;
7595               size -= 2;
7596               offset += 2;
7597             }
7598           else
7599             {
7600               if (!(left->aop->type == AOP_LIT && byteOfVal (left->aop->aopu.aop_lit, offset) == a_always_byte))
7601                 cheapMove (ASMOP_A, 0, left->aop, offset, true);
7602               a_always_byte = -1;
7603               emit3_o (A_SBC, ASMOP_A, 0, right->aop, offset);
7604               size--;
7605               offset++;
7606             }
7607         }
7608 
7609 fix:
7610       /* There is no good signed compare in the Z80, so we need workarounds */
7611       if (sign)
7612         {
7613           if (!IS_GB)           /* Directly check for overflow, can't be done on GBZ80 */
7614             {
7615               if (!regalloc_dry_run)
7616                 {
7617                   symbol *tlbl = newiTempLabel (NULL);
7618                   emit2 (IS_RAB ? "jp LZ, !tlabel" : "jp PO, !tlabel", labelKey2num (tlbl->key));
7619                   emit2 ("xor a, !immedbyte", 0x80);
7620                   emitLabelSpill (tlbl);
7621                 }
7622               regalloc_dry_run_cost += 5;
7623               result_in_carry = FALSE;
7624             }
7625           else                  /* Do it the hard way */
7626             {
7627               /* Test if one operand is negative, while the other is not. If this is the
7628                  case we can easily decide which one is greater, and we set/reset the carry
7629                  flag. If not, then the unsigned compare gave the correct result and we
7630                  don't change the carry flag. */
7631               if (!regalloc_dry_run)
7632                 {
7633                   symbol *tlbl1 = newiTempLabel (NULL);
7634                   symbol *tlbl2 = newiTempLabel (NULL);
7635                   emit2 ("bit 7, e");
7636                   emit2 ("jp Z, !tlabel", labelKey2num (tlbl1->key));
7637                   emit2 ("bit 7, d");
7638                   emit2 ("jp NZ, !tlabel", labelKey2num (tlbl2->key));
7639                   emit2 ("cp a, a");
7640                   emit2 ("jp !tlabel", labelKey2num (tlbl2->key));
7641                   emitLabelSpill (tlbl1);
7642                   emit2 ("bit 7, d");
7643                   emit2 ("jp Z, !tlabel", labelKey2num (tlbl2->key));
7644                   emit2 ("scf");
7645                   emitLabelSpill (tlbl2);
7646                 }
7647               regalloc_dry_run_cost += 20;
7648               result_in_carry = TRUE;
7649             }
7650         }
7651       else
7652         result_in_carry = TRUE;
7653     }
7654 
7655 release:
7656   if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
7657     {
7658       if (!result_in_carry)
7659         {
7660           /* Shift the sign bit up into carry */
7661           emit2 ("rlca");
7662           regalloc_dry_run_cost += 1;
7663         }
7664       outBitC (result);
7665     }
7666   else
7667     {
7668       /* if the result is used in the next
7669          ifx conditional branch then generate
7670          code a little differently */
7671       if (ifx)
7672         {
7673           if (!result_in_carry)
7674             {
7675               if (!IS_GB)
7676                 genIfxJump (ifx, "m");
7677               else
7678                 {
7679                   emit2 ("rlca");
7680                   regalloc_dry_run_cost += 1;
7681                   genIfxJump (ifx, "c");
7682                 }
7683             }
7684           else
7685             genIfxJump (ifx, "c");
7686         }
7687       else
7688         {
7689           if (!result_in_carry)
7690             {
7691               /* Shift the sign bit up into carry */
7692               emit2 ("rlca");
7693               regalloc_dry_run_cost += 1;
7694             }
7695           outBitC (result);
7696         }
7697       /* leave the result in acc */
7698     }
7699 }
7700 
7701 /*-----------------------------------------------------------------*/
7702 /* genCmpGt :- greater than comparison                             */
7703 /*-----------------------------------------------------------------*/
7704 static void
genCmpGt(iCode * ic,iCode * ifx)7705 genCmpGt (iCode * ic, iCode * ifx)
7706 {
7707   operand *left, *right, *result;
7708   sym_link *letype, *retype;
7709   int sign;
7710 
7711   left = IC_LEFT (ic);
7712   right = IC_RIGHT (ic);
7713   result = IC_RESULT (ic);
7714 
7715   sign = 0;
7716   if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
7717     {
7718       letype = getSpec (operandType (left));
7719       retype = getSpec (operandType (right));
7720       sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
7721     }
7722 
7723   /* assign the asmops */
7724   aopOp (left, ic, FALSE, FALSE);
7725   aopOp (right, ic, FALSE, FALSE);
7726   aopOp (result, ic, TRUE, FALSE);
7727 
7728   setupToPreserveCarry (AOP (result), AOP (left), AOP (right));
7729 
7730   genCmp (right, left, result, ifx, sign, ic);
7731 
7732   _G.preserveCarry = FALSE;
7733   freeAsmop (left, NULL);
7734   freeAsmop (right, NULL);
7735   freeAsmop (result, NULL);
7736 }
7737 
7738 /*-----------------------------------------------------------------*/
7739 /* genCmpLt - less than comparisons                                */
7740 /*-----------------------------------------------------------------*/
7741 static void
genCmpLt(iCode * ic,iCode * ifx)7742 genCmpLt (iCode * ic, iCode * ifx)
7743 {
7744   operand *left, *right, *result;
7745   sym_link *letype, *retype;
7746   int sign;
7747 
7748   left = IC_LEFT (ic);
7749   right = IC_RIGHT (ic);
7750   result = IC_RESULT (ic);
7751 
7752   sign = 0;
7753   if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
7754     {
7755       letype = getSpec (operandType (left));
7756       retype = getSpec (operandType (right));
7757       sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
7758     }
7759 
7760   /* assign the asmops */
7761   aopOp (left, ic, FALSE, FALSE);
7762   aopOp (right, ic, FALSE, FALSE);
7763   aopOp (result, ic, TRUE, FALSE);
7764 
7765   setupToPreserveCarry (AOP (result), AOP (left), AOP (right));
7766 
7767   genCmp (left, right, result, ifx, sign, ic);
7768 
7769   _G.preserveCarry = FALSE;
7770   freeAsmop (left, NULL);
7771   freeAsmop (right, NULL);
7772   freeAsmop (result, NULL);
7773 }
7774 
7775 /*-----------------------------------------------------------------*/
7776 /* gencjneshort - compare and jump if not equal                    */
7777 /* returns pair that still needs to be popped                      */
7778 /*-----------------------------------------------------------------*/
7779 static PAIR_ID
gencjneshort(operand * left,operand * right,symbol * lbl,const iCode * ic)7780 gencjneshort (operand *left, operand *right, symbol *lbl, const iCode *ic)
7781 {
7782   int size = max (AOP_SIZE (left), AOP_SIZE (right));
7783   int offset = 0;
7784   bool a_result = FALSE;
7785   bool next_zero;
7786 
7787   /* Swap the left and right if it makes the computation easier */
7788   if (AOP_TYPE (left) == AOP_LIT || aopInReg (right->aop, 0, A_IDX))
7789     {
7790       operand *t = right;
7791       right = left;
7792       left = t;
7793     }
7794 
7795   /* Non-destructive compare */
7796   if (aopInReg (left->aop, 0, A_IDX) && bitVectBitValue (ic->rSurv, A_IDX) &&
7797     (AOP_TYPE (right) == AOP_LIT || AOP_TYPE (right) == AOP_REG && AOP (right)->aopu.aop_reg[offset]->rIdx != IYL_IDX && AOP (right)->aopu.aop_reg[offset]->rIdx != IYH_IDX || AOP_TYPE (right) == AOP_STK))
7798     {
7799       if (AOP_TYPE (right) == AOP_LIT && !byteOfVal (AOP (right)->aopu.aop_lit, 0))
7800         emit3 (A_OR, ASMOP_A, ASMOP_A);
7801       else
7802         emit3 (A_CP, ASMOP_A, AOP (right));
7803       if (!regalloc_dry_run)
7804         emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7805       regalloc_dry_run_cost += 3;
7806     }
7807   /* if the right side is a literal then anything goes */
7808   else if (AOP_TYPE (right) == AOP_LIT)
7809     {
7810       while (size--)
7811         {
7812           next_zero = size && !byteOfVal (AOP (right)->aopu.aop_lit, offset + 1);
7813 
7814           // Test for 0 can be done more efficiently using or
7815           if (!byteOfVal (AOP (right)->aopu.aop_lit, offset))
7816             {
7817               if (!a_result)
7818                 {
7819                   cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7820                   emit3 (A_OR, ASMOP_A, ASMOP_A);
7821                 }
7822               else
7823                 emit3_o (A_OR, ASMOP_A, 0, AOP (left), offset);
7824 
7825               a_result = TRUE;
7826             }
7827           else if ((aopInReg (left->aop, 0, A_IDX) && !bitVectBitValue (ic->rSurv, A_IDX) ||
7828             AOP_TYPE (left) == AOP_REG && AOP (left)->aopu.aop_reg[offset]->rIdx != IYL_IDX && AOP (left)->aopu.aop_reg[offset]->rIdx != IYH_IDX && !bitVectBitValue (ic->rSurv, AOP (left)->aopu.aop_reg[offset]->rIdx)) &&
7829             byteOfVal (AOP (right)->aopu.aop_lit, offset) == 0x01 && !next_zero)
7830             {
7831               if(!regalloc_dry_run)
7832                 emit2 ("dec %s", aopGet (AOP (left), offset, FALSE));
7833               regalloc_dry_run_cost++;
7834               a_result = aopInReg (left->aop, 0, A_IDX);
7835             }
7836           else if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] < offset && size && byteOfVal (right->aop->aopu.aop_lit, offset) == 0xff &&
7837             (left->aop->type == AOP_REG || left->aop->type == AOP_STK) &&
7838             byteOfVal (right->aop->aopu.aop_lit, offset) == byteOfVal (right->aop->aopu.aop_lit, offset + 1))
7839             {
7840               cheapMove (ASMOP_A, 0, left->aop, offset, true);
7841               while (byteOfVal (right->aop->aopu.aop_lit, offset + 1) == 0xff && size)
7842                 {
7843                   emit3_o (A_AND, ASMOP_A, 0, left->aop, ++offset);
7844                   size--;
7845                 }
7846               emit3 (A_INC, ASMOP_A, 0);
7847               next_zero = size && !byteOfVal (AOP (right)->aopu.aop_lit, offset + 1);
7848               a_result = true;
7849             }
7850           else if ((aopInReg (left->aop, 0, A_IDX) && !bitVectBitValue (ic->rSurv, A_IDX) ||
7851             AOP_TYPE (left) == AOP_REG && AOP (left)->aopu.aop_reg[offset]->rIdx != IYL_IDX && AOP (left)->aopu.aop_reg[offset]->rIdx != IYH_IDX && !bitVectBitValue (ic->rSurv, AOP (left)->aopu.aop_reg[offset]->rIdx)) &&
7852             byteOfVal (AOP (right)->aopu.aop_lit, offset) == 0xff && !next_zero)
7853             {
7854               if(!regalloc_dry_run)
7855                 emit2 ("inc %s", aopGet (AOP (left), offset, FALSE));
7856               regalloc_dry_run_cost++;
7857               a_result = aopInReg (left->aop, 0, A_IDX);
7858             }
7859           else
7860             {
7861               cheapMove (ASMOP_A, 0, left->aop, offset, true);
7862 
7863               if (byteOfVal (right->aop->aopu.aop_lit, offset) == 0x01)
7864                 emit3 (A_DEC, ASMOP_A, 0);
7865               else if (byteOfVal (right->aop->aopu.aop_lit, offset) == 0xff)
7866                 emit3 (A_INC, ASMOP_A, 0);
7867               else
7868                 emit3_o (A_SUB, ASMOP_A, 0, right->aop, offset);
7869 
7870               a_result = true;
7871             }
7872 
7873           // Only emit jump now if there is no following test for 0 (which would just or to a current result in a)
7874           if (!(next_zero && a_result))
7875             {
7876               if (!regalloc_dry_run)
7877                 emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7878               regalloc_dry_run_cost += 3;
7879             }
7880           offset++;
7881         }
7882     }
7883   /* if the right side is in a register or
7884      pointed to by HL, IX or IY */
7885   else if (AOP_TYPE (right) == AOP_REG ||
7886            AOP_TYPE (right) == AOP_HL ||
7887            AOP_TYPE (right) == AOP_IY ||
7888            AOP_TYPE (right) == AOP_STK ||
7889            AOP_TYPE (right) == AOP_EXSTK ||
7890            AOP_TYPE (right) == AOP_IMMD ||
7891            AOP_IS_PAIRPTR (right, PAIR_HL) || AOP_IS_PAIRPTR (right, PAIR_IX) || AOP_IS_PAIRPTR (right, PAIR_IY))
7892     {
7893       while (size--)
7894         {
7895           if (aopInReg (right->aop, offset, A_IDX)  || aopInReg (right->aop, offset, HL_IDX) || aopInReg (left->aop, offset, BC_IDX) || aopInReg (left->aop, offset, DE_IDX))
7896             {
7897               operand *t = right;
7898               right = left;
7899               left = t;
7900             }
7901 
7902           if (!IS_GB && isPairDead (PAIR_HL, ic) &&
7903             (aopInReg (left->aop, offset, HL_IDX) && (aopInReg (right->aop, offset, BC_IDX) || aopInReg (right->aop, offset, DE_IDX) || getFreePairId (ic) != PAIR_INVALID) ||
7904             size == 1 && (aopInReg (right->aop, offset, BC_IDX) || aopInReg (right->aop, offset, DE_IDX))))
7905             {
7906               PAIR_ID pair = getPairId_o (right->aop, offset);
7907               if (pair == PAIR_INVALID)
7908                 pair = getFreePairId (ic);
7909 
7910               fetchPairLong (PAIR_HL, left->aop, ic, offset);
7911               fetchPairLong (pair, right->aop, 0, offset);
7912               emit3 (A_CP, ASMOP_A, ASMOP_A);
7913               emit2 ("sbc hl, %s", _pairs[pair].name);
7914               if (!regalloc_dry_run)
7915                 emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7916               regalloc_dry_run_cost += 5;
7917 
7918               offset += 2;
7919               size--;
7920               continue;
7921             }
7922 
7923           cheapMove (ASMOP_A, 0, AOP (left), offset, true);
7924           if (AOP_TYPE (right) == AOP_LIT && byteOfVal (AOP (right)->aopu.aop_lit, offset) == 0)
7925             {
7926               emit3 (A_OR, ASMOP_A, ASMOP_A);
7927               if (!regalloc_dry_run)
7928                 emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7929               regalloc_dry_run_cost += 3;
7930             }
7931           else
7932             {
7933               emit3_o (A_SUB, ASMOP_A, 0, AOP (right), offset);
7934               if (!regalloc_dry_run)
7935                 emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7936               regalloc_dry_run_cost += 3;
7937             }
7938           offset++;
7939         }
7940     }
7941   /* right is in direct space or a pointer reg, need both a & b */
7942   else
7943     {
7944       PAIR_ID pair;
7945       for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
7946         {
7947           if (((AOP_TYPE (left) != AOP_PAIRPTR) || (AOP (left)->aopu.aop_pairId != pair)) &&
7948               ((AOP_TYPE (right) != AOP_PAIRPTR) || (AOP (right)->aopu.aop_pairId != pair)))
7949             {
7950               break;
7951             }
7952         }
7953       _push (pair);
7954       while (size--)
7955         {
7956           if (!regalloc_dry_run)
7957             _emitMove (_pairs[pair].l, aopGet (AOP (left), offset, FALSE));
7958           else
7959             regalloc_dry_run_cost += ld_cost (ASMOP_E, AOP (left));
7960           cheapMove (ASMOP_A, 0, AOP (right), offset, true);
7961           emit2 ("sub a,%s", _pairs[pair].l);
7962           regalloc_dry_run_cost += 1;
7963           if (!regalloc_dry_run)
7964             emit2 ("jp NZ,!tlabel", labelKey2num (lbl->key));
7965           regalloc_dry_run_cost += 3;
7966           offset++;
7967         }
7968       return pair;
7969     }
7970   return PAIR_INVALID;
7971 }
7972 
7973 /*-----------------------------------------------------------------*/
7974 /* gencjne - compare and jump if not equal                         */
7975 /*-----------------------------------------------------------------*/
7976 static void
gencjne(operand * left,operand * right,symbol * lbl,const iCode * ic)7977 gencjne (operand * left, operand * right, symbol * lbl, const iCode *ic)
7978 {
7979   symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
7980   PAIR_ID pop;
7981 
7982   pop = gencjneshort (left, right, lbl, ic);
7983 
7984   /* PENDING: ?? */
7985   if (!regalloc_dry_run)
7986     {
7987       emit2 ("ld a,!one");
7988       emit2 ("jp !tlabel", labelKey2num (tlbl->key));
7989       emitLabelSpill (lbl);
7990       emit2 ("xor a,a");
7991       emitLabel (tlbl);
7992     }
7993   regalloc_dry_run_cost += 6;
7994   _pop (pop);
7995 }
7996 
7997 /*-----------------------------------------------------------------*/
7998 /* genCmpEq - generates code for equal to                          */
7999 /*-----------------------------------------------------------------*/
8000 static void
genCmpEq(iCode * ic,iCode * ifx)8001 genCmpEq (iCode * ic, iCode * ifx)
8002 {
8003   operand *left, *right, *result;
8004   bool hl_touched;
8005 
8006   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
8007   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
8008   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
8009 
8010   hl_touched = (AOP_TYPE (IC_LEFT (ic)) == AOP_HL || AOP_TYPE (IC_RIGHT (ic)) == AOP_HL || IS_GB
8011                 && AOP_TYPE (IC_LEFT (ic)) == AOP_STK || IS_GB && AOP_TYPE (IC_RIGHT (ic)) == AOP_STK);
8012 
8013   /* Swap operands if it makes the operation easier. ie if:
8014      1.  Left is a literal.
8015    */
8016   if (AOP_TYPE (IC_LEFT (ic)) == AOP_LIT || AOP_TYPE (IC_RIGHT (ic)) != AOP_LIT && AOP_TYPE (IC_RIGHT (ic)) != AOP_REG
8017       && AOP_TYPE (IC_LEFT (ic)) == AOP_REG)
8018     {
8019       operand *t = IC_RIGHT (ic);
8020       IC_RIGHT (ic) = IC_LEFT (ic);
8021       IC_LEFT (ic) = t;
8022     }
8023 
8024   if (ifx && !AOP_SIZE (result))
8025     {
8026       /* if they are both bit variables */
8027       if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
8028         {
8029           wassertl (0, "Tried to compare two bits");
8030         }
8031       else
8032         {
8033           PAIR_ID pop;
8034           symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8035           pop = gencjneshort (left, right, tlbl, ic);
8036           if (IC_TRUE (ifx))
8037             {
8038               if (pop != PAIR_INVALID)
8039                 {
8040                   emit2 ("pop %s", _pairs[pop].name);
8041                   regalloc_dry_run_cost += 1;
8042                 }
8043               if (!regalloc_dry_run)
8044                 emit2 ("jp !tlabel", labelKey2num (IC_TRUE (ifx)->key));
8045               regalloc_dry_run_cost += 3;
8046               if (!regalloc_dry_run)
8047                 hl_touched ? emitLabelSpill (tlbl) : emitLabel (tlbl);
8048               else if (hl_touched)
8049                 spillCached ();
8050               _pop (pop);
8051             }
8052           else
8053             {
8054               /* PENDING: do this better */
8055               symbol *lbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8056               if (pop != PAIR_INVALID)
8057                 {
8058                   emit2 ("pop %s", _pairs[pop].name);
8059                   regalloc_dry_run_cost += 1;
8060                 }
8061               if (!regalloc_dry_run)
8062                 emit2 ("jp !tlabel", labelKey2num (lbl->key));
8063               regalloc_dry_run_cost += 3;
8064               if (!regalloc_dry_run)
8065                 hl_touched ? emitLabelSpill (tlbl) : emitLabel (tlbl);
8066               else if (hl_touched)
8067                 spillCached ();
8068               _pop (pop);
8069               if (!regalloc_dry_run)
8070                 {
8071                   emit2 ("jp !tlabel", labelKey2num (IC_FALSE (ifx)->key));
8072                   emitLabel (lbl);
8073                 }
8074               regalloc_dry_run_cost += 3;
8075             }
8076         }
8077       /* mark the icode as generated */
8078       ifx->generated = 1;
8079       goto release;
8080     }
8081 
8082   /* if they are both bit variables */
8083   if (AOP_TYPE (left) == AOP_CRY && ((AOP_TYPE (right) == AOP_CRY) || (AOP_TYPE (right) == AOP_LIT)))
8084     {
8085       wassertl (0, "Tried to compare a bit to either a literal or another bit");
8086     }
8087   else
8088     {
8089       gencjne (left, right, regalloc_dry_run ? 0 : newiTempLabel (NULL), ic);
8090       if (AOP_TYPE (result) == AOP_CRY && AOP_SIZE (result))
8091         {
8092           wassert (0);
8093         }
8094       if (ifx)
8095         {
8096           genIfxJump (ifx, "a");
8097           goto release;
8098         }
8099       /* if the result is used in an arithmetic operation
8100          then put the result in place */
8101       if (AOP_TYPE (result) != AOP_CRY)
8102         outAcc (result);
8103       /* leave the result in acc */
8104     }
8105 
8106 release:
8107   freeAsmop (left, NULL);
8108   freeAsmop (right, NULL);
8109   freeAsmop (result, NULL);
8110 }
8111 
8112 /*-----------------------------------------------------------------*/
8113 /* genAndOp - for && operation                                     */
8114 /*-----------------------------------------------------------------*/
8115 static void
genAndOp(const iCode * ic)8116 genAndOp (const iCode * ic)
8117 {
8118   operand *left, *right, *result;
8119 
8120   /* note here that && operations that are in an if statement are
8121      taken away by backPatchLabels only those used in arthmetic
8122      operations remain */
8123   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
8124   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
8125   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
8126 
8127   /* if both are bit variables */
8128   if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
8129     {
8130       wassertl (0, "Tried to and two bits");
8131     }
8132   else
8133     {
8134       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8135       _toBoolean (left, TRUE);
8136       if (!regalloc_dry_run)
8137         emit2 ("jp Z,!tlabel", labelKey2num (tlbl->key));
8138       regalloc_dry_run_cost += 3;
8139       _toBoolean (right, FALSE);
8140       if (!regalloc_dry_run)
8141         emitLabel (tlbl);
8142       outBitAcc (result);
8143     }
8144 
8145   freeAsmop (left, NULL);
8146   freeAsmop (right, NULL);
8147   freeAsmop (result, NULL);
8148 }
8149 
8150 /*-----------------------------------------------------------------*/
8151 /* genOrOp - for || operation                                      */
8152 /*-----------------------------------------------------------------*/
8153 static void
genOrOp(const iCode * ic)8154 genOrOp (const iCode * ic)
8155 {
8156   operand *left, *right, *result;
8157 
8158   /* note here that || operations that are in an
8159      if statement are taken away by backPatchLabels
8160      only those used in arthmetic operations remain */
8161   aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
8162   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
8163   aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
8164 
8165   /* if both are bit variables */
8166   if (AOP_TYPE (left) == AOP_CRY && AOP_TYPE (right) == AOP_CRY)
8167     {
8168       wassertl (0, "Tried to OR two bits");
8169     }
8170   else
8171     {
8172       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8173       _toBoolean (left, TRUE);
8174       if (!regalloc_dry_run)
8175         emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
8176       regalloc_dry_run_cost += 3;
8177       _toBoolean (right, FALSE);
8178       if (!regalloc_dry_run)
8179         emitLabel (tlbl);
8180       outBitAcc (result);
8181     }
8182 
8183   freeAsmop (left, NULL);
8184   freeAsmop (right, NULL);
8185   freeAsmop (result, NULL);
8186 }
8187 
8188 /*-----------------------------------------------------------------*/
8189 /* isLiteralBit - test if lit == 2^n                               */
8190 /*-----------------------------------------------------------------*/
8191 static int
isLiteralBit(unsigned long lit)8192 isLiteralBit (unsigned long lit)
8193 {
8194   unsigned long pw[32] =
8195   {
8196     1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
8197     0x100L, 0x200L, 0x400L, 0x800L,
8198     0x1000L, 0x2000L, 0x4000L, 0x8000L,
8199     0x10000L, 0x20000L, 0x40000L, 0x80000L,
8200     0x100000L, 0x200000L, 0x400000L, 0x800000L,
8201     0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
8202     0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L
8203   };
8204   int idx;
8205 
8206   for (idx = 0; idx < 32; idx++)
8207     if (lit == pw[idx])
8208       return idx;
8209   return -1;
8210 }
8211 
8212 /*-----------------------------------------------------------------*/
8213 /* jmpTrueOrFalse -                                                */
8214 /*-----------------------------------------------------------------*/
8215 static void
jmpTrueOrFalse(iCode * ic,symbol * tlbl)8216 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
8217 {
8218   // ugly but optimized by peephole
8219   // Using emitLabelSpill instead of emitLabel (esp. on gbz80)
8220   // We could jump there from locations with different values in hl.
8221   // This should be changed to a more efficient solution that spills
8222   // only what and when necessary.
8223   if (IC_TRUE (ic))
8224     {
8225       if (!regalloc_dry_run)
8226         {
8227           symbol *nlbl = newiTempLabel (NULL);
8228           emit2 ("jp !tlabel", labelKey2num (nlbl->key));
8229           emitLabelSpill (tlbl);
8230           emit2 ("jp !tlabel", labelKey2num (IC_TRUE (ic)->key));
8231           emitLabelSpill (nlbl);
8232         }
8233       regalloc_dry_run_cost += 6;
8234     }
8235   else
8236     {
8237       if (!regalloc_dry_run)
8238         {
8239           emit2 ("jp !tlabel", labelKey2num (IC_FALSE (ic)->key));
8240           emitLabelSpill (tlbl);
8241         }
8242       regalloc_dry_run_cost += 3;
8243     }
8244   if (!regalloc_dry_run)
8245     ic->generated = 1;
8246 }
8247 
8248 /*-----------------------------------------------------------------*/
8249 /* genAnd  - code for and                                          */
8250 /*-----------------------------------------------------------------*/
8251 static void
genAnd(const iCode * ic,iCode * ifx)8252 genAnd (const iCode * ic, iCode * ifx)
8253 {
8254   operand *left, *right, *result;
8255   int size, offset = 0;
8256   unsigned long long lit = 0L;
8257   unsigned int bytelit = 0;
8258 
8259   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
8260   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
8261   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
8262 
8263   bool pushed_a = false;
8264   bool a_free = !bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= 0 && right->aop->regs[A_IDX] <= 0;
8265 
8266   /* if left is a literal & right is not then exchange them */
8267   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
8268     {
8269       operand *tmp = right;
8270       right = left;
8271       left = tmp;
8272     }
8273 
8274   /* if result = right then exchange them */
8275   if (sameRegs (AOP (result), AOP (right)) && !AOP_NEEDSACC (left))
8276     {
8277       operand *tmp = right;
8278       right = left;
8279       left = tmp;
8280     }
8281 
8282   if (AOP_TYPE (right) == AOP_LIT)
8283     lit = ullFromVal (AOP (right)->aopu.aop_lit);
8284 
8285   size = AOP_SIZE (result);
8286 
8287   if (AOP_TYPE (left) == AOP_CRY)
8288     {
8289       wassertl (0, "Tried to perform an AND with a bit as an operand");
8290       goto release;
8291     }
8292 
8293   /* Make sure A is on the left to not overwrite it. */
8294   if (aopInReg (right->aop, 0, A_IDX) ||
8295     !aopInReg (left->aop, 0, A_IDX) && isPair (AOP (right)) && (getPairId (AOP (right)) == PAIR_HL || getPairId (AOP (right)) == PAIR_IY))
8296     {
8297       operand *tmp = right;
8298       right = left;
8299       left = tmp;
8300     }
8301 
8302   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
8303   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
8304   if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
8305     {
8306       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8307       int sizel;
8308 
8309       sizel = AOP_SIZE (left);
8310       if (size)
8311         {
8312           /* PENDING: Test case for this. */
8313           emit2 ("scf");
8314           regalloc_dry_run_cost += 1;
8315         }
8316       while (sizel)
8317         {
8318           char *jumpcond = "NZ";
8319 
8320           if ((bytelit = ((lit >> (offset * 8)) & 0x0ffull)) == 0x00ull)
8321             {
8322               sizel--;
8323               offset++;
8324               continue;
8325             }
8326 
8327           /* Testing for the border bits of the accumulator destructively is cheap. */
8328           if ((isLiteralBit (bytelit) == 0 || isLiteralBit (bytelit) == 7) && aopInReg (left->aop, 0, A_IDX) && !bitVectBitValue (ic->rSurv, A_IDX))
8329             {
8330               emit3 (isLiteralBit (bytelit) == 0 ? A_RRCA : A_RLCA, 0 , 0);
8331               jumpcond = "C";
8332               sizel--;
8333               offset++;
8334             }
8335           /* Testing for the inverse of the border bits of some 32-bit registers destructively is cheap. */
8336           /* More combinations would be possible, but this one is the one that is common in the floating-point library. */
8337           else if (AOP_TYPE (left) == AOP_REG && sizel >= 4 && ((lit >> (offset * 8)) & 0xffffffffull) == 0x7fffffffull &&
8338             !IS_GB && getPartPairId (AOP (left), offset) == PAIR_HL && isPairDead (PAIR_HL, ic) &&
8339             IS_RAB && getPartPairId (AOP (left), offset + 2) == PAIR_DE && isPairDead (PAIR_HL, ic))
8340             {
8341               emit3 (A_CP, ASMOP_A, ASMOP_A); // Clear carry.
8342               emit2 ("adc hl, hl"); // Cannot use "add hl, hl instead, since it does not affect zero flag.
8343               if (!regalloc_dry_run)
8344                 emit2 ("jp NZ,!tlabel", labelKey2num (tlbl->key));
8345               emit2 ("rl de");
8346               regalloc_dry_run_cost += 6;
8347               sizel -= 4;
8348               offset += 4;
8349             }
8350           /* Testing for the inverse of the border bits of some 16-bit registers destructively is cheap. */
8351           /* More combinations would be possible, but these are the common ones. */
8352           else if (AOP_TYPE (left) == AOP_REG && sizel >= 2 && ((lit >> (offset * 8)) & 0xffffull) == 0x7fffull &&
8353             (!IS_GB && getPartPairId (AOP (left), offset) == PAIR_HL && isPairDead (PAIR_HL, ic) ||
8354             IS_RAB && getPartPairId (AOP (left), offset) == PAIR_DE  && isPairDead (PAIR_DE, ic)))
8355             {
8356               PAIR_ID pair;
8357               switch (AOP (left)->aopu.aop_reg[offset]->rIdx)
8358                 {
8359                 case L_IDX:
8360                 case H_IDX:
8361                   pair = PAIR_HL;
8362                   break;
8363                 case E_IDX:
8364                 case D_IDX:
8365                   pair = PAIR_DE;
8366                   break;
8367                 default:
8368                   pair = PAIR_INVALID;
8369                   wassertl (0, "Invalid pair");
8370                 }
8371               emit3 (A_CP, ASMOP_A, ASMOP_A); // Clear carry.
8372               if (pair == PAIR_HL)
8373                 emit2 ("adc %s, %s", _pairs[pair].name, _pairs[pair].name); // Cannot use "add hl, hl instead, since it does not affect zero flag.
8374               else
8375                 emit2 ("rl %s", _pairs[pair].name);
8376               regalloc_dry_run_cost += (pair == PAIR_DE ? 1 : 2);
8377               sizel -= 2;
8378               offset += 2;
8379             }
8380           /* Testing for the border bits of some 16-bit registers destructively is cheap. */
8381           else if (AOP_TYPE (left) == AOP_REG && sizel == 1 &&
8382             (isLiteralBit (bytelit) == 7 && (
8383               AOP (left)->aopu.aop_reg[offset]->rIdx == H_IDX && isPairDead (PAIR_HL, ic) ||
8384               IS_RAB && AOP (left)->aopu.aop_reg[offset]->rIdx == D_IDX && isPairDead (PAIR_DE, ic) ||
8385               AOP (left)->aopu.aop_reg[offset]->rIdx == IYH_IDX && isPairDead (PAIR_IY, ic)
8386             ) ||
8387             isLiteralBit (bytelit) == 0 && IS_RAB && (
8388               AOP (left)->aopu.aop_reg[offset]->rIdx == L_IDX && isPairDead (PAIR_HL, ic) ||
8389               AOP (left)->aopu.aop_reg[offset]->rIdx == E_IDX && isPairDead (PAIR_DE, ic) ||
8390               AOP (left)->aopu.aop_reg[offset]->rIdx == IYL_IDX && isPairDead (PAIR_IY, ic)
8391               )))
8392             {
8393               PAIR_ID pair;
8394               switch (AOP (left)->aopu.aop_reg[offset]->rIdx)
8395                 {
8396                 case L_IDX:
8397                 case H_IDX:
8398                   pair = PAIR_HL;
8399                   break;
8400                 case E_IDX:
8401                 case D_IDX:
8402                   pair = PAIR_DE;
8403                   break;
8404                 case IYL_IDX:
8405                 case IYH_IDX:
8406                   pair = PAIR_IY;
8407                   break;
8408                 default:
8409                   pair = PAIR_INVALID;
8410                   wassertl (0, "Invalid pair");
8411                 }
8412               if ((pair == PAIR_HL || pair == PAIR_IY) && isLiteralBit (bytelit) == 7)
8413                 emit2 ("add %s, %s", _pairs[pair].name, _pairs[pair].name);
8414               else if (isLiteralBit (bytelit) == 7)
8415                 emit2 ("rl %s", _pairs[pair].name);
8416               else
8417                 emit2 ("rr %s", _pairs[pair].name);
8418               regalloc_dry_run_cost += (pair == PAIR_IY ? 2 : 1);
8419               jumpcond = "C";
8420               sizel--;
8421               offset++;
8422             }
8423           /* Non-destructive and when exactly one bit per byte is set. */
8424           else if (isLiteralBit (bytelit) >= 0 &&
8425             (AOP_TYPE (left) == AOP_STK || aopInReg (left->aop, 0, A_IDX) || AOP_TYPE (left) == AOP_HL || AOP_TYPE (left) == AOP_IY || AOP_TYPE (left) == AOP_REG && AOP (left)->aopu.aop_reg[0]->rIdx != IYL_IDX))
8426             {
8427               if (!regalloc_dry_run)
8428                 emit2 ("bit %d, %s", isLiteralBit (bytelit), aopGet (AOP (left), offset, FALSE));
8429               regalloc_dry_run_cost += (AOP_TYPE (left) == AOP_STK || AOP_TYPE (left) == AOP_IY) ? 4 : 2;
8430               sizel--;
8431               offset++;
8432             }
8433           /* Z180 has non-destructive and. */
8434           else if ((IS_Z180 || IS_EZ80_Z80) && aopInReg (left->aop, 0, A_IDX) && bitVectBitValue (ic->rSurv, A_IDX) && bytelit != 0x0ff)
8435             {
8436               if (!regalloc_dry_run)
8437                 emit2 ("tst a, %s", aopGet (AOP (right), 0, FALSE));
8438               regalloc_dry_run_cost += (AOP_TYPE (right) == AOP_LIT ? 3 : 2);
8439               sizel--;
8440               offset++;
8441             }
8442           /* Generic case, loading into accumulator and testing there. */
8443           else
8444             {
8445               if (bitVectBitValue (ic->rSurv, A_IDX) || left->aop->regs[A_IDX] > offset || right->aop->regs[A_IDX] > offset)
8446                 {
8447                   regalloc_dry_run_cost += 100;
8448                   wassert (regalloc_dry_run);
8449                 }
8450 
8451               cheapMove (ASMOP_A, 0, left->aop, offset, true);
8452               if (isLiteralBit (bytelit) == 0 || isLiteralBit (bytelit) == 7)
8453                 {
8454                   emit3 (isLiteralBit (bytelit) == 0 ? A_RRCA : A_RLCA, 0 , 0);
8455                   jumpcond = "C";
8456                 }
8457               else if (bytelit != 0xffu)
8458                 emit3_o (A_AND, ASMOP_A, 0, AOP (right), offset);
8459               else
8460                 emit3 (A_OR, ASMOP_A, ASMOP_A);     /* For the flags */
8461               sizel--;
8462               offset++;
8463             }
8464           if (size || ifx)  /* emit jmp only, if it is actually used */
8465             {
8466               if (!regalloc_dry_run)
8467                 emit2 ("jp %s,!tlabel", jumpcond, labelKey2num (tlbl->key));
8468               regalloc_dry_run_cost += 3;
8469             }
8470         }
8471       // bit = left & literal
8472       if (size)
8473         {
8474           emit2 ("clr c");
8475           if (!regalloc_dry_run)
8476             emit2 ("!tlabeldef", labelKey2num (tlbl->key));
8477           regalloc_dry_run_cost += 3;
8478           genLine.lineCurr->isLabel = 1;
8479         }
8480       // if(left & literal)
8481       else
8482         {
8483           if (ifx)
8484             jmpTrueOrFalse (ifx, tlbl);
8485           goto release;
8486         }
8487       outBitC (result);
8488       goto release;
8489     }
8490 
8491   if (IS_RAB && isPair (AOP (result)) &&
8492       (getPairId (AOP (result)) == PAIR_HL && isPair (AOP (right)) && getPairId (AOP (right)) == PAIR_DE ||
8493        getPairId (AOP (result)) == PAIR_HL && isPair (AOP (left)) && getPairId (AOP (left)) == PAIR_DE ||
8494        isPair (AOP (left)) && getPairId (AOP (left)) == PAIR_IY && getPairId (AOP (result)) == PAIR_IY && isPair (AOP (right))
8495        && getPairId (AOP (right)) == PAIR_DE))
8496     {
8497       if (isPair (AOP (left)) && getPairId (AOP (left)) == PAIR_DE)
8498         fetchPair (PAIR_HL, AOP (right));
8499       else                      /* right operand in DE */
8500         fetchPair (getPairId (AOP (result)), AOP (left));
8501       emit2 ("and hl, de");
8502       regalloc_dry_run_cost += (getPairId (AOP (result)) == PAIR_HL ? 1 : 2);
8503       goto release;
8504     }
8505 
8506   wassertl (AOP_TYPE (result) != AOP_CRY, "Result of and is in a bit");
8507 
8508   for (int i = 0; i < size;)
8509     {
8510       if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= i && right->aop->regs[A_IDX] <= i && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= i))
8511         a_free = true;
8512 
8513       if (pushed_a && (aopInReg (left->aop, i, A_IDX) || aopInReg (right->aop, i, A_IDX)))
8514         {
8515           _pop (PAIR_AF);
8516           if (bitVectBitValue (ic->rSurv, A_IDX))
8517             _push (PAIR_AF);
8518           else
8519             pushed_a = false;
8520         }
8521 
8522       if (AOP_TYPE (right) == AOP_LIT)
8523         {
8524           bytelit = byteOfVal (right->aop->aopu.aop_lit, i);
8525 
8526           if (bytelit == 0x00)
8527             {
8528               cheapMove (result->aop, i, ASMOP_ZERO, 0, a_free);
8529               if (aopInReg (result->aop, i, A_IDX))
8530                 a_free = false;
8531               i++;
8532               continue;
8533             }
8534           else if (bytelit == 0xff)
8535             {
8536               cheapMove (result->aop, i, AOP (left), i, a_free);
8537               if (aopInReg (result->aop, i, A_IDX))
8538                 a_free = false;
8539               i++;
8540               continue;
8541             }
8542           else if (isLiteralBit (~bytelit & 0xffu) >= 0 &&
8543             (AOP_TYPE (result) == AOP_REG || left == right && (AOP_TYPE (result) == AOP_STK || AOP_TYPE (result) == AOP_DIR)))
8544             {
8545               cheapMove (result->aop, i, left->aop, i, a_free);
8546               if (!regalloc_dry_run)
8547                 emit2 ("res %d, %s", isLiteralBit (~bytelit & 0xffu), aopGet (result->aop, i, false));
8548               regalloc_dry_run_cost += 2;
8549               if (aopInReg (result->aop, i, A_IDX))
8550                 a_free = false;
8551               i++;
8552               continue;
8553             }
8554           else if (IS_RAB &&
8555             (aopInReg (result->aop, i, HL_IDX) && (aopInReg (left->aop, i, HL_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, DE_IDX)) ||
8556             aopInReg (result->aop, i, H_IDX) && aopInReg (result->aop, i + 1, L_IDX) && (aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i + 1, L_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, D_IDX) && aopInReg (left->aop, i + 1, E_IDX))))
8557             {
8558               unsigned short mask = aopInReg (result->aop, i, L_IDX) ? (bytelit + (byteOfVal (right->aop->aopu.aop_lit, i + 1) << 8)) : (byteOfVal (right->aop->aopu.aop_lit, i + 1) + (bytelit << 8));
8559               bool mask_in_de = (aopInReg (left->aop, i, L_IDX) | aopInReg (left->aop, i, H_IDX));
8560               emit2 (mask_in_de ? "ld de, !immedword" : "ld hl, !immedword", mask);
8561               emit2 ("and hl, de");
8562               regalloc_dry_run_cost += 4;
8563               i += 2;
8564               continue;
8565             }
8566         }
8567 
8568       if (IS_RAB)
8569         {
8570           const bool this_byte_l = aopInReg (result->aop, i, L_IDX) &&
8571             (aopInReg (left->aop, i, L_IDX) && aopInReg (left->aop, i, E_IDX) || aopInReg (left->aop, i, E_IDX) && aopInReg (left->aop, i, L_IDX));
8572           const bool this_byte_h = aopInReg (result->aop, i, H_IDX) &&
8573             (aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i, D_IDX) || aopInReg (left->aop, i, D_IDX) && aopInReg (left->aop, i, H_IDX));
8574           const bool next_byte_l = aopInReg (result->aop, i + 1, L_IDX) &&
8575             (aopInReg (left->aop, i + 1, L_IDX) && aopInReg (left->aop, i + 1, E_IDX) || aopInReg (left->aop, i + 1, E_IDX) && aopInReg (left->aop, i + 1, L_IDX));
8576           const bool next_byte_h = aopInReg (result->aop, i + 1, H_IDX) &&
8577             (aopInReg (left->aop, i + 1, H_IDX) && aopInReg (left->aop, i + 1, D_IDX) || aopInReg (left->aop, i + 1, D_IDX) && aopInReg (left->aop, i + 1, H_IDX));
8578 
8579           const bool this_byte = this_byte_l || this_byte_h;
8580           const bool next_byte = next_byte_l || next_byte_h;
8581 
8582           const bool next_byte_unused = !bitVectBitValue (ic->rMask, this_byte_l ? H_IDX : L_IDX);
8583 
8584           if (this_byte && (next_byte || next_byte_unused))
8585             {
8586               emit2 ("and hl, de");
8587               regalloc_dry_run_cost++;
8588               i += (1 + next_byte);
8589               continue;
8590             }
8591         }
8592 
8593       if (!a_free)
8594         {
8595           wassert (!pushed_a);
8596           _push (PAIR_AF);
8597           pushed_a = true;
8598           a_free = true;
8599         }
8600 
8601       // Use plain and in a.
8602       if (aopInReg (right->aop, i, A_IDX))
8603         emit3_o (A_AND, ASMOP_A, 0, left->aop, i);
8604       else
8605         {
8606           cheapMove (ASMOP_A, 0, left->aop, i, true);
8607           emit3_o (A_AND, ASMOP_A, 0, right->aop, i);
8608         }
8609       cheapMove (result->aop, i, ASMOP_A, 0, true);
8610 
8611       if (aopInReg (result->aop, i, A_IDX))
8612         a_free = false;
8613 
8614       i++;
8615     }
8616   if (pushed_a)
8617     _pop (PAIR_AF);
8618 
8619 release:
8620   freeAsmop (left, NULL);
8621   freeAsmop (right, NULL);
8622   freeAsmop (result, NULL);
8623 }
8624 
8625 /*-----------------------------------------------------------------*/
8626 /* genOr  - code for or                                            */
8627 /*-----------------------------------------------------------------*/
8628 static void
genOr(const iCode * ic,iCode * ifx)8629 genOr (const iCode * ic, iCode * ifx)
8630 {
8631   operand *left, *right, *result;
8632   int size, offset = 0;
8633   unsigned long long lit = 0;
8634   int bytelit = 0;
8635 
8636   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
8637   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
8638   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
8639 
8640   bool pushed_a = false;
8641   bool a_free = !bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= 0 && right->aop->regs[A_IDX] <= 0;
8642 
8643   /* if left is a literal & right is not then exchange them */
8644   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
8645     {
8646       operand *tmp = right;
8647       right = left;
8648       left = tmp;
8649     }
8650 
8651   /* if result = right then exchange them */
8652   if (sameRegs (AOP (result), AOP (right)) && !AOP_NEEDSACC (left))
8653     {
8654       operand *tmp = right;
8655       right = left;
8656       left = tmp;
8657     }
8658 
8659   if (AOP_TYPE (right) == AOP_LIT)
8660     lit = ullFromVal (AOP (right)->aopu.aop_lit);
8661 
8662   size = AOP_SIZE (result);
8663 
8664   if (AOP_TYPE (left) == AOP_CRY)
8665     {
8666       wassertl (0, "Tried to OR where left is a bit");
8667       goto release;
8668     }
8669 
8670   /* Make sure A is on the left to not overwrite it. */
8671   if (aopInReg (right->aop, 0, A_IDX))
8672     {
8673       operand *tmp = right;
8674       right = left;
8675       left = tmp;
8676     }
8677 
8678   // if(val | 0xZZ)       - size = 0, ifx != FALSE  -
8679   // bit = val | 0xZZ     - size = 1, ifx = FALSE -
8680   if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
8681     {
8682       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8683       int sizel;
8684 
8685       sizel = AOP_SIZE (left);
8686 
8687       if (size)
8688         {
8689           wassertl (0, "Result is assigned to a bit");
8690         }
8691       /* PENDING: Modeled after the AND code which is inefficient. */
8692       while (sizel--)
8693         {
8694           if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= offset && right->aop->regs[A_IDX] <= offset && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= offset))
8695             a_free = true;
8696 
8697           if (!a_free) // Hard to handle pop with ifx
8698             {
8699                regalloc_dry_run_cost += 100;
8700                wassert (regalloc_dry_run);
8701             }
8702 
8703           bytelit = (lit >> (offset * 8)) & 0x0FFull;
8704 
8705           cheapMove (ASMOP_A, 0, left->aop, offset, true);
8706 
8707           if (bytelit != 0)
8708             emit3_o (A_OR, ASMOP_A, 0, AOP (right), offset);
8709           else if (ifx)
8710             {
8711               /* For the flags */
8712               emit3 (A_OR, ASMOP_A, ASMOP_A);
8713             }
8714 
8715           if (ifx)              /* emit jmp only, if it is actually used */
8716             {
8717               if (!regalloc_dry_run)
8718                 emit2 ("jp NZ,!tlabel", labelKey2num (tlbl->key));
8719               regalloc_dry_run_cost += 3;
8720             }
8721 
8722           offset++;
8723         }
8724       if (ifx)
8725         {
8726           jmpTrueOrFalse (ifx, tlbl);
8727         }
8728       goto release;
8729     }
8730 
8731   wassertl (AOP_TYPE (result) != AOP_CRY, "Result of or is in a bit");
8732 
8733   for (int i = 0; i < size;)
8734     {
8735       if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= i && right->aop->regs[A_IDX] <= i && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= i))
8736         a_free = true;
8737 
8738       if (pushed_a && (aopInReg (left->aop, i, A_IDX) || aopInReg (right->aop, i, A_IDX)))
8739         {
8740           _pop (PAIR_AF);
8741           if (bitVectBitValue (ic->rSurv, A_IDX))
8742             _push (PAIR_AF);
8743           else
8744             pushed_a = false;
8745         }
8746 
8747       if (AOP_TYPE (right) == AOP_LIT)
8748         {
8749           bytelit = byteOfVal (right->aop->aopu.aop_lit, i);
8750 
8751           if (bytelit == 0xff)
8752             {
8753               // TODO
8754             }
8755           else if (bytelit == 0x00)
8756             {
8757               cheapMove (result->aop, i, left->aop, i, a_free);
8758               if (aopInReg (result->aop, i, A_IDX))
8759                 a_free = false;
8760               i++;
8761               continue;
8762             }
8763           else if (isLiteralBit (bytelit) >= 0 &&
8764             (AOP_TYPE (result) == AOP_REG || left == right && (AOP_TYPE (result) == AOP_STK || AOP_TYPE (result) == AOP_DIR)))
8765             {
8766               cheapMove (result->aop, i, left->aop, i, a_free);
8767               if (!regalloc_dry_run)
8768                 emit2 ("set %d, %s", isLiteralBit (bytelit), aopGet (result->aop, i, false));
8769               regalloc_dry_run_cost += 2;
8770               if (aopInReg (result->aop, i, A_IDX))
8771                 a_free = false;
8772               i++;
8773               continue;
8774             }
8775           else if (IS_RAB &&
8776             (aopInReg (result->aop, i, HL_IDX) && (aopInReg (left->aop, i, HL_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, DE_IDX)) ||
8777             aopInReg (result->aop, i, H_IDX) && aopInReg (result->aop, i + 1, L_IDX) && (aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i + 1, L_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, D_IDX) && aopInReg (left->aop, i + 1, E_IDX))))
8778             {
8779               unsigned short mask = aopInReg (result->aop, i, L_IDX) ? (bytelit + (byteOfVal (right->aop->aopu.aop_lit, i + 1) << 8)) : (byteOfVal (right->aop->aopu.aop_lit, i + 1) + (bytelit << 8));
8780               bool mask_in_de = (aopInReg (left->aop, i, L_IDX) | aopInReg (left->aop, i, H_IDX));
8781               emit2 (mask_in_de ? "ld de, !immedword" : "ld hl, !immedword", mask);
8782               emit2 ("or hl, de");
8783               regalloc_dry_run_cost += 4;
8784               i += 2;
8785               continue;
8786             }
8787         }
8788 
8789       if (IS_RAB)
8790         {
8791           const bool this_byte_l = aopInReg (result->aop, i, L_IDX) &&
8792             (aopInReg (left->aop, i, L_IDX) && aopInReg (left->aop, i, E_IDX) || aopInReg (left->aop, i, E_IDX) && aopInReg (left->aop, i, L_IDX));
8793           const bool this_byte_h = aopInReg (result->aop, i, H_IDX) &&
8794             (aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i, D_IDX) || aopInReg (left->aop, i, D_IDX) && aopInReg (left->aop, i, H_IDX));
8795           const bool next_byte_l = aopInReg (result->aop, i + 1, L_IDX) &&
8796             (aopInReg (left->aop, i + 1, L_IDX) && aopInReg (left->aop, i + 1, E_IDX) || aopInReg (left->aop, i + 1, E_IDX) && aopInReg (left->aop, i + 1, L_IDX));
8797           const bool next_byte_h = aopInReg (result->aop, i + 1, H_IDX) &&
8798             (aopInReg (left->aop, i + 1, H_IDX) && aopInReg (left->aop, i + 1, D_IDX) || aopInReg (left->aop, i + 1, D_IDX) && aopInReg (left->aop, i + 1, H_IDX));
8799 
8800           const bool this_byte = this_byte_l || this_byte_h;
8801           const bool next_byte = next_byte_l || next_byte_h;
8802 
8803           const bool next_byte_unused = !bitVectBitValue (ic->rMask, this_byte_l ? H_IDX : L_IDX);
8804 
8805           if (this_byte && (next_byte || next_byte_unused))
8806             {
8807               emit2 ("or hl, de");
8808               regalloc_dry_run_cost++;
8809               i += (1 + next_byte);
8810               continue;
8811             }
8812         }
8813 
8814       // Use plain or in a.
8815       if (!a_free)
8816         {
8817           wassert (!pushed_a);
8818           _push (PAIR_AF);
8819           pushed_a = true;
8820           a_free = true;
8821         }
8822 
8823       if (aopInReg (right->aop, i, A_IDX))
8824         emit3_o (A_OR, ASMOP_A, 0, left->aop, i);
8825       else
8826         {
8827           cheapMove (ASMOP_A, 0, left->aop, i, true);
8828           emit3_o (A_OR, ASMOP_A, 0, right->aop, i);
8829         }
8830       cheapMove (result->aop, i, ASMOP_A, 0, true);
8831       if (aopInReg (result->aop, i, A_IDX))
8832         a_free = false;
8833       i++;
8834     }
8835 
8836   if (pushed_a)
8837     _pop (PAIR_AF);
8838 
8839 release:
8840   freeAsmop (left, NULL);
8841   freeAsmop (right, NULL);
8842   freeAsmop (result, NULL);
8843 }
8844 
8845 /*-----------------------------------------------------------------*/
8846 /* genXor - code for xclusive or                                   */
8847 /*-----------------------------------------------------------------*/
8848 static void
genXor(const iCode * ic,iCode * ifx)8849 genXor (const iCode *ic, iCode *ifx)
8850 {
8851   operand *left, *right, *result;
8852   int size, offset = 0;
8853   unsigned long long lit = 0;
8854   bool pushed_a = false;
8855 
8856   aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
8857   aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
8858   aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
8859 
8860   bool a_free = !bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= 0 && right->aop->regs[A_IDX] <= 0;
8861 
8862   /* if left is a literal & right is not then exchange them */
8863   if ((AOP_TYPE (left) == AOP_LIT && AOP_TYPE (right) != AOP_LIT) || (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
8864     {
8865       operand *tmp = right;
8866       right = left;
8867       left = tmp;
8868     }
8869 
8870   /* if result = right then exchange them */
8871   if (sameRegs (result->aop, AOP (right)) && !AOP_NEEDSACC (left))
8872     {
8873       operand *tmp = right;
8874       right = left;
8875       left = tmp;
8876     }
8877 
8878   if (AOP_TYPE (right) == AOP_LIT)
8879     lit = ullFromVal (AOP (right)->aopu.aop_lit);
8880 
8881   size = AOP_SIZE (result);
8882 
8883   if (AOP_TYPE (left) == AOP_CRY)
8884     {
8885       wassertl (0, "Tried to XOR a bit");
8886       goto release;
8887     }
8888 
8889   /* Make sure A is on the left to not overwrite it. */
8890   if (aopInReg (right->aop, 0, A_IDX))
8891     {
8892       wassert (!AOP_NEEDSACC (left));
8893       operand *tmp = right;
8894       right = left;
8895       left = tmp;
8896     }
8897 
8898   // if(val & 0xZZ)       - size = 0, ifx != FALSE  -
8899   // bit = val & 0xZZ     - size = 1, ifx = FALSE -
8900   if ((AOP_TYPE (right) == AOP_LIT) && (AOP_TYPE (result) == AOP_CRY) && (AOP_TYPE (left) != AOP_CRY))
8901     {
8902       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
8903       int sizel;
8904 
8905       sizel = AOP_SIZE (left);
8906 
8907       if (size)
8908         {
8909           /* PENDING: Test case for this. */
8910           wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
8911         }
8912       while (sizel--)
8913         {
8914           if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= offset && right->aop->regs[A_IDX] <= offset && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= offset))
8915             a_free = true;
8916 
8917           if (!a_free)
8918             {
8919               wassert (!pushed_a);
8920               _push (PAIR_AF);
8921               a_free = true;
8922               pushed_a = true;
8923               if (ifx) // The pop at the end is hard to eal with in case of ifx.
8924                 {
8925                   regalloc_dry_run_cost += 100;
8926                   wassert (regalloc_dry_run);
8927                 }
8928             }
8929           else if (pushed_a && (aopInReg (left->aop, offset, A_IDX) || aopInReg (right->aop, offset, A_IDX)))
8930             {
8931               _pop (PAIR_AF);
8932               if (bitVectBitValue (ic->rSurv, A_IDX))
8933                 _push (PAIR_AF);
8934               else
8935                 pushed_a = false;
8936             }
8937 
8938           if (aopInReg (right->aop, offset, A_IDX))
8939             emit3_o (A_XOR, ASMOP_A, 0, left->aop, offset);
8940           else
8941             {
8942               cheapMove (ASMOP_A, 0, left->aop, offset, true);
8943               emit3_o (A_XOR, ASMOP_A, 0, right->aop, offset);
8944             }
8945           if (ifx)              /* emit jmp only, if it is actually used * */
8946             if (!regalloc_dry_run)
8947               emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
8948           regalloc_dry_run_cost += 3;
8949           offset++;
8950         }
8951       if (pushed_a)
8952         _pop (PAIR_AF);
8953       if (ifx)
8954         {
8955           jmpTrueOrFalse (ifx, tlbl);
8956         }
8957       else if (size)
8958         {
8959           wassertl (0, "Result of XOR was destined for a bit");
8960         }
8961       goto release;
8962     }
8963 
8964     // left & result in different registers
8965     if (AOP_TYPE (result) == AOP_CRY)
8966       {
8967         wassertl (0, "Result of XOR is in a bit");
8968       }
8969     else
8970       for (; (size--); offset++)
8971         {
8972           if (!bitVectBitValue (ic->rSurv, A_IDX) && left->aop->regs[A_IDX] <= offset && right->aop->regs[A_IDX] <= offset && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= offset))
8973             a_free = true;
8974 
8975           if (pushed_a && (aopInReg (left->aop, offset, A_IDX) || aopInReg (right->aop, offset, A_IDX)))
8976             {
8977               _pop (PAIR_AF);
8978               if (bitVectBitValue (ic->rSurv, A_IDX))
8979                 _push (PAIR_AF);
8980               else
8981                 pushed_a = false;
8982             }
8983 
8984           // normal case
8985           // result = left & right
8986           if (right->aop->type == AOP_LIT)
8987             {
8988               if (((lit >> (offset * 8)) & 0x0FFL) == 0x00L)
8989                 {
8990                   cheapMove (result->aop, offset, left->aop, offset, a_free);
8991                   if (aopInReg (result->aop, offset, A_IDX))
8992                     a_free = false;
8993                   continue;
8994                 }
8995             }
8996           // faster than result <- left, anl result,right
8997           // and better if result is SFR
8998           if (!a_free)
8999             {
9000               wassert (!pushed_a);
9001               _push (PAIR_AF);
9002               a_free = true;
9003               pushed_a = true;
9004             }
9005 
9006           if (aopInReg (right->aop, offset, A_IDX))
9007             emit3_o (A_XOR, ASMOP_A, 0, left->aop, offset);
9008           else
9009             {
9010               cheapMove (ASMOP_A, 0, left->aop, offset, true);
9011               if (right->aop->type == AOP_LIT && ((lit >> (offset * 8)) & 0xff) == 0xff)
9012                 emit3 (A_CPL, 0, 0);
9013               else
9014                 emit3_o (A_XOR, ASMOP_A, 0, right->aop, offset);
9015             }
9016           cheapMove (result->aop, offset, ASMOP_A, 0, true);
9017           if (aopInReg (result->aop, offset, A_IDX))
9018             a_free = false;
9019         }
9020   if (pushed_a)
9021      _pop (PAIR_AF);
9022 
9023 release:
9024   freeAsmop (left, NULL);
9025   freeAsmop (right, NULL);
9026   freeAsmop (result, NULL);
9027 }
9028 
9029 /*-----------------------------------------------------------------*/
9030 /* genRRC - rotate right with carry                                */
9031 /*-----------------------------------------------------------------*/
9032 static void
genRRC(const iCode * ic)9033 genRRC (const iCode * ic)
9034 {
9035   wassert (0);
9036 }
9037 
9038 /*-----------------------------------------------------------------*/
9039 /* genRLC - generate code for rotate left with carry               */
9040 /*-----------------------------------------------------------------*/
9041 static void
genRLC(const iCode * ic)9042 genRLC (const iCode * ic)
9043 {
9044   wassert (0);
9045 }
9046 
9047 /*-----------------------------------------------------------------*/
9048 /* genGetHbit - generates code get highest order bit               */
9049 /*-----------------------------------------------------------------*/
9050 static void
genGetHbit(const iCode * ic)9051 genGetHbit (const iCode * ic)
9052 {
9053   operand *left, *result;
9054   left = IC_LEFT (ic);
9055   result = IC_RESULT (ic);
9056 
9057   aopOp (left, ic, FALSE, FALSE);
9058   aopOp (result, ic, FALSE, FALSE);
9059 
9060   /* get the highest order byte into a */
9061   cheapMove (ASMOP_A, 0, left->aop, AOP_SIZE (left) - 1, true);
9062 
9063   if (AOP_TYPE (result) == AOP_CRY)
9064     {
9065       emit3 (A_RL, ASMOP_A, 0);
9066       outBitC (result);
9067     }
9068   else
9069     {
9070       emit3 (A_RLC, ASMOP_A, 0);
9071       emit2 ("and a, !one");
9072       regalloc_dry_run_cost += 2;
9073       outAcc (result);
9074     }
9075 
9076 
9077   freeAsmop (left, NULL);
9078   freeAsmop (result, NULL);
9079 }
9080 
9081 /*-----------------------------------------------------------------*/
9082 /* genGetAbit - generates code get a single bit                    */
9083 /*-----------------------------------------------------------------*/
9084 static void
genGetAbit(const iCode * ic)9085 genGetAbit (const iCode * ic)
9086 {
9087   wassert (0);
9088 }
9089 
9090 static void
emitRsh2(asmop * aop,int size,int is_signed)9091 emitRsh2 (asmop * aop, int size, int is_signed)
9092 {
9093   int offset = 0;
9094 
9095   while (size--)
9096     {
9097       if (offset == 0)
9098         emit3_o (is_signed ? A_SRA : A_SRL, aop, size, 0, 0);
9099       else
9100         emit3_o (A_RR, aop, size, 0, 0);
9101       offset++;
9102     }
9103 }
9104 
9105 /*-----------------------------------------------------------------*/
9106 /* shiftR2Left2Result - shift right two bytes from left to result  */
9107 /*-----------------------------------------------------------------*/
9108 static void
shiftR2Left2Result(const iCode * ic,operand * left,int offl,operand * result,int offr,int shCount,int is_signed)9109 shiftR2Left2Result (const iCode *ic, operand *left, int offl, operand *result, int offr, int shCount, int is_signed)
9110 {
9111   int size = 2;
9112   symbol *tlbl;
9113 
9114   if (IS_RAB && !is_signed && shCount < 4 &&
9115     (getPairId (AOP (result)) == PAIR_HL || getPairId (AOP (result)) == PAIR_DE))
9116     {
9117       bool op_de = (getPairId (AOP (result)) == PAIR_DE);
9118       fetchPairLong (getPairId (AOP (result)), AOP(left), ic, offl);
9119       while (shCount--)
9120         {
9121           emit3 (A_CP, ASMOP_A, ASMOP_A);
9122           emit2 (op_de? "rr de" : "rr hl");
9123           regalloc_dry_run_cost++;
9124         }
9125       return;
9126     }
9127   else if (IS_RAB && !is_signed && shCount >= 2 && isPairDead (PAIR_HL, ic) &&
9128       ((isPair (AOP (left)) && getPairId (AOP (left)) == PAIR_HL || isPair (AOP (result))
9129         && getPairId (AOP (result)) == PAIR_HL) && isPairDead (PAIR_DE, ic) || isPair (AOP (left))
9130        && getPairId (AOP (left)) == PAIR_DE))
9131     {
9132       bool op_de = (getPairId (AOP (left)) == PAIR_DE);
9133       if (op_de)
9134         emit2 ("ld hl, !immedword", 0xffff >> shCount);
9135       else
9136         {
9137           fetchPair (PAIR_HL, AOP (left));
9138           emit2 ("ld de, !immedword", 0xffff >> shCount);
9139         }
9140       regalloc_dry_run_cost += 3;
9141       while (shCount--)
9142         {
9143           emit2 (op_de ? "rr de" : "rr hl");
9144           regalloc_dry_run_cost++;
9145         }
9146       emit2 ("and hl, de");
9147       regalloc_dry_run_cost += 1;
9148       commitPair (AOP (IC_RESULT (ic)), PAIR_HL, ic, TRUE);
9149       return;
9150     }
9151 
9152   if (isPair (AOP (result)) && !offr)
9153     fetchPairLong (getPairId (AOP (result)), AOP(left), ic, offl);
9154   else
9155     genMove_o (result->aop, offr, left->aop, offl, 2, true, isPairDead (PAIR_HL, ic));
9156 
9157   if (shCount == 0)
9158     return;
9159 
9160   /*  if (AOP(result)->type == AOP_REG) { */
9161 
9162   /* Left is already in result - so now do the shift */
9163   /* Optimizing for speed by default. */
9164   if (!optimize.codeSize || shCount <= 2)
9165     {
9166       while (shCount--)
9167         {
9168           emitRsh2 (AOP (result), size, is_signed);
9169         }
9170     }
9171   else
9172     {
9173       bool use_b = (!IS_GB && !bitVectBitValue (ic->rSurv, B_IDX)
9174                     && !(AOP_TYPE (result) == AOP_REG
9175                          && (AOP (result)->aopu.aop_reg[0]->rIdx == B_IDX || AOP (result)->aopu.aop_reg[1]->rIdx == B_IDX)));
9176 
9177       tlbl = regalloc_dry_run ? 0 : newiTempLabel (NULL);
9178 
9179       if (!regalloc_dry_run)
9180         {
9181           emit2 ("ld %s, !immedbyte", use_b ? "b" : "a", shCount);
9182           emitLabel (tlbl);
9183         }
9184       regalloc_dry_run_cost += 2;
9185 
9186       emitRsh2 (AOP (result), size, is_signed);
9187 
9188       if (!regalloc_dry_run)
9189         {
9190           if (use_b)
9191             emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
9192           else
9193             {
9194               emit2 ("dec a");
9195               emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
9196             }
9197         }
9198       regalloc_dry_run_cost += use_b ? 2 : 4;
9199     }
9200 }
9201 
9202 /*-----------------------------------------------------------------*/
9203 /* shiftL2Left2Result - shift left two bytes from left to result   */
9204 /*-----------------------------------------------------------------*/
9205 static void
shiftL2Left2Result(operand * left,int offl,operand * result,int offr,int shCount,const iCode * ic)9206 shiftL2Left2Result (operand *left, int offl, operand *result, int offr, int shCount, const iCode *ic)
9207 {
9208   operand *shiftoperand = result;
9209 
9210   if (sameRegs (AOP (result), AOP (left)) && ((offl + MSB16) == offr))
9211     {
9212       wassert (0);
9213     }
9214 
9215   /* For a shift of 7 we can use cheaper right shifts */
9216   else if (shCount == 7 && AOP_TYPE (left) == AOP_REG && !bitVectBitValue (ic->rSurv, AOP (left)->aopu.aop_reg[0]->rIdx) && AOP_TYPE (result) == AOP_REG &&
9217     AOP (left)->aopu.aop_reg[0]->rIdx != IYL_IDX && AOP (left)->aopu.aop_reg[1]->rIdx != IYL_IDX && AOP (left)->aopu.aop_reg[0]->rIdx != IYH_IDX && AOP (left)->aopu.aop_reg[1]->rIdx != IYH_IDX &&
9218     AOP (result)->aopu.aop_reg[0]->rIdx != IYL_IDX && AOP (result)->aopu.aop_reg[1]->rIdx != IYL_IDX && AOP (result)->aopu.aop_reg[0]->rIdx != IYH_IDX && AOP (result)->aopu.aop_reg[1]->rIdx != IYH_IDX &&
9219     (optimize.codeSpeed || getPairId (AOP (result)) != PAIR_HL || getPairId (AOP (left)) != PAIR_HL)) /* but a sequence of add hl, hl might still be cheaper code-size wise */
9220     {
9221       // Handling the low byte in A with xor clearing is cheaper.
9222       bool special_a = (!bitVectBitValue (ic->rSurv, A_IDX) && !aopInReg (AOP (left), 0, A_IDX) && !aopInReg (AOP (left), 0, A_IDX));
9223       asmop *lowbyte = special_a ? ASMOP_A : AOP (result);
9224 
9225       if (special_a)
9226         emit3 (A_XOR, ASMOP_A, ASMOP_A);
9227       emit3_o (A_RR, AOP (left), 1, 0, 0);
9228       emit3_o (A_LD, AOP (result), 1, AOP (left), 0);
9229       emit3_o (A_RR, AOP (result), 1, 0, 0);
9230       if (!special_a)
9231         emit3_o (A_LD, AOP (result), 0, ASMOP_ZERO, 0);
9232       if (aopInReg (lowbyte, 0, A_IDX))
9233         emit3 (A_RRA, 0, 0);
9234       else
9235         emit3 (A_RR, lowbyte, 0);
9236       if (special_a)
9237         cheapMove (result->aop, 0, lowbyte, 0, true);
9238       return;
9239     }
9240 
9241   if (AOP_TYPE (result) != AOP_REG && AOP_TYPE (left) == AOP_REG && AOP_SIZE (left) >= 2 && !bitVectBitValue (ic->rSurv, AOP (left)->aopu.aop_reg[0]->rIdx) && !bitVectBitValue (ic->rSurv, AOP (left)->aopu.aop_reg[1]->rIdx) ||
9242     getPairId (AOP (left)) == PAIR_HL && isPairDead (PAIR_HL, ic))
9243     shiftoperand = left;
9244   else if (isPair (AOP (result)) && !offr)
9245     fetchPairLong (getPairId (AOP (result)), AOP(left), ic, offl);
9246   else
9247     genMove_o (result->aop, offr, left->aop, offl, 2, true, isPairDead (PAIR_HL, ic));
9248 
9249   if (shCount == 0)
9250     ;
9251   else if (getPairId (AOP (shiftoperand)) == PAIR_HL)
9252     {
9253       while (shCount--)
9254         {
9255           emit2 ("add hl, hl");
9256           regalloc_dry_run_cost += 1;
9257         }
9258     }
9259   else if (getPairId (AOP (shiftoperand)) == PAIR_IY)
9260     {
9261       while (shCount--)
9262         {
9263           emit2 ("add iy, iy");
9264           regalloc_dry_run_cost += 2;
9265         }
9266     }
9267   else if (IS_RAB && getPairId (AOP (shiftoperand)) == PAIR_DE)
9268     {
9269       while (shCount--)
9270         {
9271           emit3 (A_CP, ASMOP_A, ASMOP_A);
9272           emit2 ("rl de");
9273           regalloc_dry_run_cost++;
9274         }
9275     }
9276   else
9277     {
9278       int size = 2;
9279       int offset = 0;
9280       symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
9281       symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel (0);
9282 
9283       if (AOP (shiftoperand)->type == AOP_REG)
9284         {
9285           while (shCount--)
9286             {
9287               for (offset = 0; offset < size; offset++)
9288                 emit3_o (offset ? A_RL : A_SLA, AOP (shiftoperand), offset, 0, 0);
9289             }
9290         }
9291       else
9292         {
9293           /* Left is already in result - so now do the shift */
9294           if (shCount > 1)
9295             {
9296               if (!regalloc_dry_run)
9297                 {
9298                   emit2 ("ld a, !immedbyte+1", shCount);
9299                   emit2 ("jp !tlabel", labelKey2num (tlbl1->key));
9300                   emitLabel (tlbl);
9301                 }
9302               regalloc_dry_run_cost += 4;
9303             }
9304 
9305           while (size--)
9306             {
9307               emit3_o (offset ? A_RL : A_SLA, AOP (shiftoperand), offset, 0, 0);
9308 
9309               offset++;
9310             }
9311           if (shCount > 1)
9312             {
9313               if (!regalloc_dry_run)
9314                 {
9315                   emitLabel (tlbl1);
9316                   emit2 ("dec a");
9317                   emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
9318                 }
9319               regalloc_dry_run_cost += 4;
9320             }
9321         }
9322     }
9323 
9324   if (shiftoperand != result)
9325     {
9326       if (isPair (AOP (result)) && !offr)
9327         fetchPairLong (getPairId (AOP (result)), AOP(shiftoperand), ic, offl);
9328       else if (isPair (AOP (shiftoperand)))
9329         commitPair (AOP (result), getPairId (AOP (shiftoperand)), ic, FALSE);
9330       else
9331         {
9332           /* Copy left into result */
9333           movLeft2Result (shiftoperand, offl, result, offr, 0);
9334           movLeft2Result (shiftoperand, offl + 1, result, offr + 1, 0);
9335         }
9336     }
9337 }
9338 
9339 /*-----------------------------------------------------------------*/
9340 /* AccRol - rotate left accumulator by known count                 */
9341 /*-----------------------------------------------------------------*/
9342 static void
AccRol(int shCount)9343 AccRol (int shCount)
9344 {
9345   shCount &= 0x0007;            // shCount : 0..7
9346 
9347   switch (shCount)
9348     {
9349     case 4:
9350       if (IS_GB)
9351         {
9352           emit3 (A_SWAP, ASMOP_A, 0);
9353           break;
9354         }
9355       emit3 (A_RLCA, 0, 0);
9356     case 3:
9357       if (IS_GB)
9358         {
9359           emit3 (A_SWAP, ASMOP_A, 0);
9360           emit3 (A_RRCA, 0, 0);
9361           break;
9362         }
9363       emit3 (A_RLCA, 0, 0);
9364     case 2:
9365       emit3 (A_RLCA, 0, 0);
9366     case 1:
9367       emit3 (A_RLCA, 0, 0);
9368     case 0:
9369       break;
9370     case 5:
9371       if (IS_GB)
9372         {
9373           emit3 (A_SWAP, ASMOP_A, 0);
9374           emit3 (A_RLCA, 0, 0);
9375           break;
9376         }
9377       emit3 (A_RRCA, 0, 0);
9378     case 6:
9379       emit3 (A_RRCA, 0, 0);
9380     case 7:
9381       emit3 (A_RRCA, 0, 0);
9382       break;
9383     }
9384 }
9385 
9386 /*-----------------------------------------------------------------*/
9387 /* AccLsh - left shift accumulator by known count                  */
9388 /*-----------------------------------------------------------------*/
9389 static void
AccLsh(unsigned int shCount)9390 AccLsh (unsigned int shCount)
9391 {
9392   static const unsigned char SLMask[] =
9393   {
9394     0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
9395   };
9396 
9397   if (shCount <= 3 + !IS_GB)
9398     while (shCount--)
9399       emit3 (A_ADD, ASMOP_A, ASMOP_A);
9400   else
9401     {
9402       /* rotate left accumulator */
9403       AccRol (shCount);
9404       /* and kill the lower order bits */
9405       emit2 ("and a, !immedbyte", SLMask[shCount]);
9406       regalloc_dry_run_cost += 2;
9407     }
9408 }
9409 
9410 /*-----------------------------------------------------------------*/
9411 /* shiftL1Left2Result - shift left one byte from left to result    */
9412 /*-----------------------------------------------------------------*/
9413 static void
shiftL1Left2Result(operand * left,int offl,operand * result,int offr,unsigned int shCount,const iCode * ic)9414 shiftL1Left2Result (operand *left, int offl, operand *result, int offr, unsigned int shCount, const iCode *ic)
9415 {
9416   /* If operand and result are the same we can shift in place.
9417      However shifting in acc using add is cheaper than shifting
9418      in place using sla; when shifting by more than 2 shifting in
9419      acc it is worth the additional effort for loading from / to acc. */
9420   if (!aopInReg(result->aop, 0, A_IDX) && sameRegs (AOP (left), AOP (result)) && shCount <= 2 && offr == offl)
9421     {
9422       while (shCount--)
9423         emit3 (A_SLA, AOP (result), 0);
9424     }
9425   else if ((IS_Z180 && !optimize.codeSpeed || IS_EZ80_Z80) && // Try to use mlt
9426     (aopInReg (result->aop, offr, C_IDX) && isPairDead(PAIR_BC, ic) || aopInReg (result->aop, offr, E_IDX) && isPairDead(PAIR_DE, ic) || aopInReg (result->aop, offr, L_IDX) && isPairDead(PAIR_HL, ic)))
9427     {
9428       PAIR_ID pair = aopInReg (result->aop, offr, C_IDX) ? PAIR_BC : (aopInReg (result->aop, offr, E_IDX) ? PAIR_DE : PAIR_HL);
9429 
9430       bool top = aopInReg (left->aop, offl, _pairs[pair].h_idx);
9431       if (!top)
9432         cheapMove (pair == PAIR_BC ? ASMOP_C : (pair == PAIR_DE ? ASMOP_E : ASMOP_L), 0, left->aop, offl, !bitVectBitValue (ic->rSurv, A_IDX));
9433 
9434       emit2 ("ld %s, #%d", top ? _pairs[pair].l : _pairs[pair].h, 1 << shCount);
9435       emit2 ("mlt %s", _pairs[pair].name);
9436       regalloc_dry_run_cost += 4;
9437     }
9438   else
9439     {
9440       if (bitVectBitValue (ic->rSurv, A_IDX))
9441         _push (PAIR_AF);
9442       cheapMove (ASMOP_A, 0, left->aop, offl, true);
9443       /* shift left accumulator */
9444       AccLsh (shCount);
9445       cheapMove (AOP (result), offr, ASMOP_A, 0, true);
9446       if (bitVectBitValue (ic->rSurv, A_IDX))
9447         _pop (PAIR_AF);
9448     }
9449 }
9450 
9451 /*-----------------------------------------------------------------*/
9452 /* genlshTwo - left shift two bytes by known amount                */
9453 /*-----------------------------------------------------------------*/
9454 static void
genlshTwo(operand * result,operand * left,unsigned int shCount,const iCode * ic)9455 genlshTwo (operand *result, operand *left, unsigned int shCount, const iCode *ic)
9456 {
9457   int size = AOP_SIZE (result);
9458 
9459   wassert (size == 2);
9460 
9461   /* if shCount >= 8 */
9462   if (shCount >= 8)
9463     {
9464       shCount -= 8;
9465       if (size > 1)
9466         {
9467           if (shCount)
9468             shiftL1Left2Result (left, 0, result, 1, shCount, ic);
9469           else
9470             movLeft2Result (left, LSB, result, MSB16, 0);
9471         }
9472       cheapMove (result->aop, 0, ASMOP_ZERO, 0, true);
9473     }
9474   /*  0 <= shCount <= 7 */
9475   else
9476     {
9477       if (size == 1)
9478         {
9479           wassert (0);
9480         }
9481       else
9482         {
9483           shiftL2Left2Result (left, LSB, result, LSB, shCount, ic);
9484         }
9485     }
9486 }
9487 
9488 /*------------------------------------------------------------------*/
9489 /* genLeftShiftLiteral - left shifting by known count for size <= 2 */
9490 /*------------------------------------------------------------------*/
9491 static void
genLeftShiftLiteral(operand * left,operand * right,operand * result,const iCode * ic)9492 genLeftShiftLiteral (operand *left, operand *right, operand *result, const iCode *ic)
9493 {
9494   unsigned int shCount = ulFromVal (AOP (right)->aopu.aop_lit);
9495   unsigned int size;
9496 
9497   freeAsmop (right, NULL);
9498 
9499   aopOp (left, ic, FALSE, FALSE);
9500   aopOp (result, ic, FALSE, FALSE);
9501 
9502   size = getSize (operandType (result));
9503 
9504   /* I suppose that the left size >= result size */
9505   wassert (getSize (operandType (left)) >= size);
9506 
9507   if (shCount >= (size * 8))
9508     genMove (result->aop, ASMOP_ZERO, !bitVectBitValue (ic->rSurv, A_IDX), isPairDead (PAIR_HL, ic) && left->aop->regs[H_IDX] < 0 && left->aop->regs[L_IDX] < 0);
9509   else
9510     {
9511       switch (size)
9512         {
9513         case 1:
9514           shiftL1Left2Result (left, 0, result, 0, shCount, ic);
9515           break;
9516         case 2:
9517           genlshTwo (result, left, shCount, ic);
9518           break;
9519         case 4:
9520           wassertl (0, "Shifting of longs should be handled by generic function.");
9521           break;
9522         default:
9523           wassert (0);
9524         }
9525     }
9526   freeAsmop (left, NULL);
9527   freeAsmop (result, NULL);
9528 }
9529 
9530 /*-----------------------------------------------------------------*/
9531 /* genLeftShift - generates code for left shifting                 */
9532 /*-----------------------------------------------------------------*/
9533 static void
genLeftShift(const iCode * ic)9534 genLeftShift (const iCode *ic)
9535 {
9536   int size, offset;
9537   symbol *tlbl = 0, *tlbl1 = 0;
9538   operand *left, *right, *result;
9539   int countreg;
9540   bool shift_by_lit;
9541   int shiftcount = 0;
9542   int byteshift = 0;
9543   bool started;
9544   bool save_a;
9545 
9546   right = IC_RIGHT (ic);
9547   left = IC_LEFT (ic);
9548   result = IC_RESULT (ic);
9549 
9550   aopOp (right, ic, FALSE, FALSE);
9551 
9552   /* if the shift count is known then do it
9553      as efficiently as possible */
9554   if (AOP_TYPE (right) == AOP_LIT && getSize (operandType (result)) <= 2)
9555     {
9556       genLeftShiftLiteral (left, right, result, ic);
9557       freeAsmop (right, NULL);
9558       return;
9559     }
9560 
9561   /* Useful for the case of shifting a size > 2 value by a literal */
9562   shift_by_lit = AOP_TYPE (right) == AOP_LIT;
9563   if (shift_by_lit)
9564     shiftcount = ulFromVal (AOP (right)->aopu.aop_lit);
9565 
9566   aopOp (result, ic, FALSE, FALSE);
9567   aopOp (left, ic, FALSE, FALSE);
9568 
9569   if (AOP_TYPE (right) == AOP_REG && !bitVectBitValue (ic->rSurv, AOP (right)->aopu.aop_reg[0]->rIdx) && AOP (right)->aopu.aop_reg[0]->rIdx != IYL_IDX && (sameRegs (AOP (left), AOP (result)) || AOP_TYPE (left) != AOP_REG) &&
9570     (AOP_TYPE (result) != AOP_REG ||
9571     AOP (result)->aopu.aop_reg[0]->rIdx != AOP (right)->aopu.aop_reg[0]->rIdx &&
9572     !aopInReg (AOP (result), 0, AOP (right)->aopu.aop_reg[0]->rIdx) && !aopInReg (AOP (result), 1, AOP (right)->aopu.aop_reg[0]->rIdx) && !aopInReg (AOP (result), 2, AOP (right)->aopu.aop_reg[0]->rIdx) && !aopInReg (AOP (result), 3, AOP (right)->aopu.aop_reg[0]->rIdx)))
9573     countreg = AOP (right)->aopu.aop_reg[0]->rIdx;
9574   else if (!IS_GB && !bitVectBitValue (ic->rSurv, B_IDX) && (sameRegs (AOP (left), AOP (result)) || AOP_TYPE (left) != AOP_REG || shift_by_lit) &&
9575     !aopInReg (AOP (result), 0, B_IDX) && !aopInReg (AOP (result), 1, B_IDX) && !aopInReg (AOP (result), 2, B_IDX) && !aopInReg (AOP (result), 3, B_IDX))
9576     countreg = B_IDX;
9577   else
9578     countreg = A_IDX;
9579 
9580   if (!shift_by_lit)
9581     cheapMove (asmopregs[countreg], 0, right->aop, 0, true);
9582 
9583   save_a = (countreg == A_IDX && !shift_by_lit) &&
9584     !(AOP_TYPE (left) == AOP_REG && AOP_TYPE (result) != AOP_REG ||
9585     !IS_GB && (AOP_TYPE (left) == AOP_STK && canAssignToPtr3 (result->aop) || AOP_TYPE (result) == AOP_STK && canAssignToPtr3 (left->aop)));
9586 
9587   /* now move the left to the result if they are not the
9588      same */
9589   if (!sameRegs (AOP (left), AOP (result)))
9590     {
9591       if (save_a)
9592         _push (PAIR_AF);
9593 
9594       if (shift_by_lit)
9595       {
9596         byteshift = shiftcount / 8;
9597         shiftcount %= 8;
9598       }
9599       size = AOP_SIZE (result) - byteshift;
9600       int lsize = AOP_SIZE (left) - byteshift;
9601 
9602       genMove_o (result->aop, byteshift, left->aop, 0, size <= lsize ? size : lsize, save_a || countreg != A_IDX, false);
9603 
9604       genMove_o (result->aop, 0, ASMOP_ZERO, 0, byteshift, save_a || countreg != A_IDX, false);
9605 
9606       if (save_a)
9607         _pop (PAIR_AF);
9608     }
9609 
9610   if (!regalloc_dry_run)
9611     {
9612       tlbl = newiTempLabel (NULL);
9613       tlbl1 = newiTempLabel (NULL);
9614     }
9615   size = AOP_SIZE (result);
9616   offset = 0;
9617 
9618   if (shift_by_lit && !shiftcount)
9619     goto end;
9620   if (shift_by_lit && shiftcount > 1)
9621     {
9622       emit2 ("ld %s, !immedbyte", countreg == A_IDX ? "a" : regsZ80[countreg].name, shiftcount);
9623       regalloc_dry_run_cost += 2;
9624     }
9625   else if (!shift_by_lit)
9626     {
9627       emit2 ("inc %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
9628       regalloc_dry_run_cost += 1;
9629       if (!regalloc_dry_run)
9630         emit2 ("jp !tlabel", labelKey2num (tlbl1->key));
9631       regalloc_dry_run_cost += 3;
9632     }
9633   if (!(shift_by_lit && shiftcount == 1) && !regalloc_dry_run)
9634     emitLabel (tlbl);
9635 
9636   if (requiresHL (AOP (result)))
9637     spillPair (PAIR_HL);
9638 
9639   started = false;
9640   while (size)
9641     {
9642       if (size >= 2 && offset + 1 >= byteshift &&
9643          AOP_TYPE (result) == AOP_REG &&
9644         (getPartPairId (AOP (result), offset) == PAIR_HL ||
9645          IS_RAB && getPartPairId (AOP (result), offset) == PAIR_DE))
9646         {
9647           if (AOP (result)->aopu.aop_reg[offset]->rIdx == L_IDX)
9648           {
9649             emit2 (started ? "adc hl, hl" : "add hl, hl");
9650             regalloc_dry_run_cost += 1 + started;
9651           }
9652           else
9653           {
9654             if (!started)
9655               emit3 (A_CP, ASMOP_A, ASMOP_A);
9656             emit2 ("rl de");
9657             regalloc_dry_run_cost++;
9658           }
9659 
9660           started = true;
9661           size -= 2, offset += 2;
9662         }
9663       else
9664         {
9665           if (offset >= byteshift)
9666             {
9667               if (aopInReg (AOP (result) , offset, A_IDX))
9668                 emit3 (started ? A_ADC : A_ADD, ASMOP_A, ASMOP_A);
9669               else
9670                 emit3_o (started ? A_RL : A_SLA, AOP (result), offset, 0, 0);
9671               started = true;
9672             }
9673           size--, offset++;
9674         }
9675     }
9676 
9677   if (!(shift_by_lit && shiftcount == 1))
9678     {
9679       if (!regalloc_dry_run)
9680         emitLabel (tlbl1);
9681       if (!IS_GB && countreg == B_IDX)
9682         {
9683           if (!regalloc_dry_run)
9684             emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
9685           regalloc_dry_run_cost += 2;
9686         }
9687       else
9688         {
9689           emit2 ("dec %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
9690           if (!regalloc_dry_run)
9691             emit2 ("jr NZ,!tlabel", labelKey2num (tlbl->key));
9692           regalloc_dry_run_cost += 3;
9693         }
9694     }
9695 
9696 end:
9697   if (!shift_by_lit && requiresHL (AOP (result))) // Shift by 0 skips over hl adjustments.
9698     spillPair (PAIR_HL);
9699 
9700   freeAsmop (left, NULL);
9701   freeAsmop (right, NULL);
9702   freeAsmop (result, NULL);
9703 }
9704 
9705 /*-----------------------------------------------------------------*/
9706 /* AccRsh - right shift accumulator by known count                 */
9707 /*-----------------------------------------------------------------*/
9708 static void
AccRsh(int shCount)9709 AccRsh (int shCount)
9710 {
9711   if (shCount >= 2)
9712     {
9713       /* rotate right accumulator */
9714       AccRol (8 - shCount);
9715       /* and kill the higher order bits */
9716       if (!regalloc_dry_run)
9717         emit2 ("and a, !immedbyte", 0xff >> shCount);
9718       regalloc_dry_run_cost += 2;
9719     }
9720   else if(shCount)
9721     emit3 (A_SRL, ASMOP_A, 0);
9722 }
9723 
9724 /*-----------------------------------------------------------------*/
9725 /* genrshOne - right shift one byte by known amount                */
9726 /*-----------------------------------------------------------------*/
9727 static void
genrshOne(operand * result,operand * left,int shCount,int is_signed,const iCode * ic)9728 genrshOne (operand *result, operand *left, int shCount, int is_signed, const iCode *ic)
9729 {
9730   /* Errk */
9731   int size = AOP_SIZE (result);
9732 
9733   wassert (size == 1);
9734 
9735   bool a_dead = !bitVectBitValue (ic->rSurv, A_IDX);
9736 
9737   if ((IS_Z180 || IS_EZ80_Z80) && !is_signed && shCount >= 3 && shCount <= 6 + a_dead && // Try to use mlt.
9738     (aopInReg (result->aop, 0, B_IDX) && isPairDead(PAIR_BC, ic) || aopInReg (result->aop, 0, D_IDX) && isPairDead(PAIR_DE, ic) || aopInReg (result->aop, 0, H_IDX) && isPairDead(PAIR_HL, ic)))
9739     {
9740       PAIR_ID pair = aopInReg (result->aop, 0, B_IDX) ? PAIR_BC : (aopInReg (result->aop, 0, D_IDX) ? PAIR_DE : PAIR_HL);
9741       bool top = aopInReg (left->aop, 0, _pairs[pair].h_idx);
9742       if (!top)
9743         cheapMove (pair == PAIR_BC ? ASMOP_C : (pair == PAIR_DE ? ASMOP_E : ASMOP_L), 0, left->aop, 0, a_dead);
9744 
9745       emit2 ("ld %s, #%d", top ? _pairs[pair].l : _pairs[pair].h, 1 << (8 - shCount));
9746       emit2 ("mlt %s", _pairs[pair].name);
9747       regalloc_dry_run_cost += 4;
9748     }
9749   else if (!is_signed && // Shifting in the accumulator is cheap for unsigned operands.
9750     (aopInReg (result->aop, 0, A_IDX) ||
9751     result->aop->type != AOP_REG ||
9752     (shCount >= 4 + 2 * a_dead || shCount >= 2 * a_dead && aopInReg (left->aop, 0, A_IDX))))
9753     {
9754       if (!a_dead)
9755         _push (PAIR_AF);
9756       cheapMove (ASMOP_A, 0, left->aop, 0, true);
9757       AccRsh (shCount);
9758       cheapMove (result->aop, 0, ASMOP_A, 0, true);
9759       if (!a_dead)
9760         _pop (PAIR_AF);
9761     }
9762   else if (AOP (result)->type == AOP_REG) // Can shift in destination for register result.
9763     {
9764       cheapMove (AOP (result), 0, AOP (left), 0, a_dead);
9765 
9766       while (shCount--)
9767         emit3 (is_signed ? A_SRA : A_SRL, result->aop, 0);
9768     }
9769   else
9770     {
9771       if (!a_dead)
9772         _push (PAIR_AF);
9773       cheapMove (ASMOP_A, 0, left->aop, 0, true);
9774       while (shCount--)
9775         emit3 (is_signed ? A_SRA : A_SRL, ASMOP_A, 0);
9776       cheapMove (result->aop, 0, ASMOP_A, 0, true);
9777       if (!a_dead)
9778         _pop (PAIR_AF);
9779     }
9780 }
9781 
9782 /*-----------------------------------------------------------------*/
9783 /* shiftR1Left2Result - shift right one byte from left to result   */
9784 /*-----------------------------------------------------------------*/
9785 static void
shiftR1Left2Result(operand * left,int offl,operand * result,int offr,int shCount,int sign)9786 shiftR1Left2Result (operand *left, int offl, operand *result, int offr, int shCount, int sign)
9787 {
9788   cheapMove (ASMOP_A, 0, left->aop, offl, true);
9789   if (sign)
9790     {
9791       while (shCount--)
9792         emit3 (sign ? A_SRA : A_SRL, ASMOP_A, 0);
9793     }
9794   else
9795     AccRsh (shCount);
9796   cheapMove (result->aop, offr, ASMOP_A, 0, true);
9797 }
9798 
9799 /*-----------------------------------------------------------------*/
9800 /* genrshTwo - right shift two bytes by known amount               */
9801 /*-----------------------------------------------------------------*/
9802 static void
genrshTwo(const iCode * ic,operand * result,operand * left,int shCount,int sign)9803 genrshTwo (const iCode * ic, operand * result, operand * left, int shCount, int sign)
9804 {
9805   /* if shCount >= 8 */
9806   if (shCount >= 8)
9807     {
9808       shCount -= 8;
9809       if (shCount)
9810         {
9811           shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
9812         }
9813       else
9814         {
9815           movLeft2Result (left, MSB16, result, LSB, sign);
9816         }
9817       if (sign)
9818         {
9819           /* Sign extend the result */
9820           cheapMove (ASMOP_A, 0, result->aop, 0, true);
9821           emit3 (A_RLC, ASMOP_A, 0);
9822           emit3 (A_SBC, ASMOP_A, ASMOP_A);
9823           cheapMove (result->aop, 1, ASMOP_A, 0, true);
9824         }
9825       else
9826         cheapMove (result->aop, 1, ASMOP_ZERO, 0, true);
9827     }
9828   /*  0 <= shCount <= 7 */
9829   else
9830     shiftR2Left2Result (ic, left, LSB, result, LSB, shCount, sign);
9831 }
9832 
9833 /*-----------------------------------------------------------------*/
9834 /* genRightShiftLiteral - right shifting by known count              */
9835 /*-----------------------------------------------------------------*/
9836 static void
genRightShiftLiteral(operand * left,operand * right,operand * result,const iCode * ic,int sign)9837 genRightShiftLiteral (operand * left, operand * right, operand * result, const iCode *ic, int sign)
9838 {
9839   unsigned int shCount = (unsigned int) ulFromVal (AOP (right)->aopu.aop_lit);
9840   unsigned int size;
9841 
9842   freeAsmop (right, NULL);
9843 
9844   aopOp (left, ic, FALSE, FALSE);
9845   aopOp (result, ic, FALSE, FALSE);
9846 
9847   size = getSize (operandType (result));
9848 
9849   /* I suppose that the left size >= result size */
9850   wassert (getSize (operandType (left)) >= size);
9851 
9852   if (shCount >= (size * 8))
9853     {
9854       if (!SPEC_USIGN (getSpec (operandType (left))))
9855         {
9856           cheapMove (ASMOP_A, 0, left->aop, 0, true);
9857           emit3 (A_RLC, ASMOP_A, 0);
9858           emit3 (A_SBC, ASMOP_A, ASMOP_A);
9859           while (size--)
9860             cheapMove (result->aop, size, ASMOP_A, 0, true);
9861         }
9862       else
9863         genMove (result->aop, ASMOP_ZERO, !bitVectBitValue (ic->rSurv, A_IDX), isPairDead (PAIR_HL, ic));
9864     }
9865   else
9866     {
9867       switch (size)
9868         {
9869         case 1:
9870           genrshOne (result, left, shCount, sign, ic);
9871           break;
9872         case 2:
9873           genrshTwo (ic, result, left, shCount, sign);
9874           break;
9875         case 4:
9876           wassertl (0, "Asked to shift right a long which should be handled in generic right shift function.");
9877           break;
9878         default:
9879           wassertl (0, "Entered default case in right shift delegate");
9880         }
9881     }
9882   freeAsmop (left, NULL);
9883   freeAsmop (result, NULL);
9884 }
9885 
9886 /*-----------------------------------------------------------------*/
9887 /* genRightShift - generate code for right shifting                */
9888 /*-----------------------------------------------------------------*/
9889 static void
genRightShift(const iCode * ic)9890 genRightShift (const iCode * ic)
9891 {
9892   operand *right, *left, *result;
9893   sym_link *retype;
9894   int size, offset, first = 1;
9895   bool is_signed;
9896   int countreg;
9897   bool shift_by_lit, shift_by_one, shift_by_zero;
9898   int shiftcount = 0;
9899   int byteoffset = 0;
9900   bool save_a;
9901 
9902   symbol *tlbl = 0, *tlbl1 = 0;
9903 
9904   /* if signed then we do it the hard way preserve the
9905      sign bit moving it inwards */
9906   retype = getSpec (operandType (IC_RESULT (ic)));
9907 
9908   is_signed = !SPEC_USIGN (retype);
9909 
9910   right = IC_RIGHT (ic);
9911   left = IC_LEFT (ic);
9912   result = IC_RESULT (ic);
9913 
9914   aopOp (right, ic, FALSE, FALSE);
9915 
9916   /* if the shift count is known then do it
9917      as efficiently as possible */
9918   if (AOP_TYPE (right) == AOP_LIT && getSize (operandType (result)) <= 2)
9919     {
9920       genRightShiftLiteral (left, right, result, ic, is_signed);
9921       freeAsmop (right, NULL);
9922       return;
9923     }
9924 
9925   /* Useful for the case of shifting a size > 2 value by a literal */
9926   shift_by_lit = AOP_TYPE (right) == AOP_LIT;
9927   if (shift_by_lit)
9928     shiftcount = ulFromVal (AOP (right)->aopu.aop_lit);
9929 
9930   aopOp (result, ic, FALSE, FALSE);
9931   aopOp (left, ic, FALSE, FALSE);
9932 
9933   if (AOP_TYPE (right) == AOP_REG && !bitVectBitValue (ic->rSurv, AOP (right)->aopu.aop_reg[0]->rIdx) && AOP (right)->aopu.aop_reg[0]->rIdx != IYL_IDX && (sameRegs (AOP (left), AOP (result)) || AOP_TYPE (left) != AOP_REG) &&
9934     (AOP_TYPE (result) != AOP_REG ||
9935     AOP (result)->aopu.aop_reg[0]->rIdx != AOP (right)->aopu.aop_reg[0]->rIdx &&
9936     (AOP_SIZE (result) < 2 || AOP (result)->aopu.aop_reg[1]->rIdx != AOP (right)->aopu.aop_reg[0]->rIdx &&
9937     (AOP_SIZE (result) < 3 || AOP (result)->aopu.aop_reg[2]->rIdx != AOP (right)->aopu.aop_reg[0]->rIdx &&
9938     (AOP_SIZE (result) < 4 || AOP (result)->aopu.aop_reg[3]->rIdx != AOP (right)->aopu.aop_reg[0]->rIdx)))))
9939     countreg = AOP (right)->aopu.aop_reg[0]->rIdx;
9940   else if (!IS_GB && !bitVectBitValue (ic->rSurv, B_IDX) && (sameRegs (AOP (left), AOP (result)) || AOP_TYPE (left) != AOP_REG || shift_by_lit) &&
9941     (AOP_TYPE (result) != AOP_REG ||
9942     AOP (result)->aopu.aop_reg[0]->rIdx != B_IDX &&
9943     (AOP_SIZE (result) < 2 || AOP (result)->aopu.aop_reg[1]->rIdx != B_IDX &&
9944     (AOP_SIZE (result) < 3 || AOP (result)->aopu.aop_reg[2]->rIdx != B_IDX &&
9945     (AOP_SIZE (result) < 4 || AOP (result)->aopu.aop_reg[3]->rIdx != B_IDX)))))
9946     countreg = B_IDX;
9947   else
9948     countreg = A_IDX;
9949 
9950   if (!shift_by_lit)
9951     cheapMove (countreg == A_IDX ? ASMOP_A : asmopregs[countreg], 0, right->aop, 0, true);
9952 
9953   save_a = (countreg == A_IDX && !shift_by_lit) &&
9954     !(AOP_TYPE (left) == AOP_REG && AOP_TYPE (result) != AOP_REG ||
9955     !IS_GB && (AOP_TYPE (left) == AOP_STK && canAssignToPtr3 (result->aop) || AOP_TYPE (result) == AOP_STK && canAssignToPtr3 (left->aop)));
9956 
9957   /* now move the left to the result if they are not the
9958      same */
9959   if (!sameRegs (AOP (left), AOP (result)))
9960     {
9961       int soffset = 0;
9962       size = AOP_SIZE (result);
9963 
9964       if (!is_signed && shift_by_lit)
9965       {
9966         byteoffset = shiftcount / 8;
9967         shiftcount %= 8;
9968         soffset = byteoffset;
9969         size -= byteoffset;
9970       }
9971 
9972       if (save_a)
9973         _push (PAIR_AF);
9974 
9975       genMove_o (result->aop, 0, left->aop, soffset, size, true, isPairDead (PAIR_HL, ic));
9976 
9977       genMove_o (result->aop, result->aop->size - byteoffset, ASMOP_ZERO, 0, byteoffset, true, false);
9978 
9979       if (save_a)
9980         _pop (PAIR_AF);
9981     }
9982 
9983   shift_by_one = (shift_by_lit && shiftcount == 1);
9984   shift_by_zero = (shift_by_lit && shiftcount == 0);
9985 
9986   if (!regalloc_dry_run)
9987     {
9988       tlbl = newiTempLabel (NULL);
9989       tlbl1 = newiTempLabel (NULL);
9990     }
9991   size = AOP_SIZE (result);
9992   offset = size - 1;
9993 
9994   if (shift_by_zero)
9995     goto end;
9996   else if (shift_by_lit && shiftcount > 1)
9997     {
9998       emit2 ("ld %s, !immedbyte", countreg == A_IDX ? "a" : regsZ80[countreg].name, shiftcount);
9999       regalloc_dry_run_cost += 2;
10000     }
10001   else if (!shift_by_lit)
10002     {
10003       emit2 ("inc %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
10004       regalloc_dry_run_cost += 1;
10005       if (!regalloc_dry_run)
10006         emit2 ("jp !tlabel", labelKey2num (tlbl1->key));
10007       regalloc_dry_run_cost += 3;
10008     }
10009   if (!shift_by_one && !regalloc_dry_run)
10010     IS_GB ? emitLabelSpill (tlbl) : emitLabel (tlbl);
10011 
10012   if (requiresHL (AOP (result)))
10013     spillPair (PAIR_HL);
10014 
10015   while (size)
10016     {
10017       if (IS_RAB && !(is_signed && first) && size >= 2 && byteoffset < 2 && AOP_TYPE (result) == AOP_REG &&
10018         (getPartPairId (AOP (result), offset - 1) == PAIR_HL || getPartPairId (AOP (result), offset - 1) == PAIR_DE))
10019         {
10020           if (first)
10021             {
10022               emit3 (A_CP, ASMOP_A, ASMOP_A);
10023               first = 0;
10024             }
10025           emit2 (AOP (result)->aopu.aop_reg[offset - 1]->rIdx == L_IDX ? "rr hl" : "rr de");
10026           regalloc_dry_run_cost++;
10027           size -= 2, offset -= 2;
10028         }
10029       else if (!is_signed && first && byteoffset--) // Skip known 0 bytes
10030         size--, offset--;
10031       else if (first)
10032         {
10033           emit3_o (is_signed ? A_SRA : A_SRL, AOP (result), offset, 0, 0);
10034           first = 0;
10035           size--, offset--;
10036         }
10037       else
10038         {
10039           emit3_o (A_RR, AOP (result), offset, 0, 0);
10040           size--, offset--;
10041         }
10042     }
10043 
10044   if (!shift_by_one)
10045     {
10046       if (!regalloc_dry_run)
10047         emitLabel (tlbl1);
10048       if (!IS_GB && countreg == B_IDX)
10049         {
10050           if (!regalloc_dry_run)
10051             emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
10052           regalloc_dry_run_cost += 2;
10053         }
10054       else
10055         {
10056           emit2 ("dec %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
10057           if (!regalloc_dry_run)
10058             emit2 ("jr NZ, !tlabel", labelKey2num (tlbl->key));
10059           regalloc_dry_run_cost += 3;
10060         }
10061     }
10062 
10063 end:
10064   if (!shift_by_lit && requiresHL (AOP (result))) // Shift by 0 skips over hl adjustments.
10065     spillPair (PAIR_HL);
10066 
10067   freeAsmop (left, NULL);
10068   freeAsmop (right, NULL);
10069   freeAsmop (result, NULL);
10070 }
10071 
10072 /*-----------------------------------------------------------------*/
10073 /* unpackMaskA - generate masking code for unpacking last byte     */
10074 /* of bitfiled. And mask for unsigned, sign extension for signed.  */
10075 /*-----------------------------------------------------------------*/
10076 static void
unpackMaskA(sym_link * type,int len)10077 unpackMaskA(sym_link *type, int len)
10078 {
10079   if (SPEC_USIGN (type) || len != 1)
10080     {
10081       emit2 ("and a, !immedbyte", ((unsigned char) - 1) >> (8 - len));
10082       regalloc_dry_run_cost += 2;
10083     }
10084   if (!SPEC_USIGN (type))
10085     {
10086       if (len == 1)
10087         {
10088           emit3(A_RRA, 0, 0);
10089           emit3(A_SBC, ASMOP_A, ASMOP_A);
10090         }
10091       else
10092         {
10093           if (!regalloc_dry_run)
10094             {
10095               symbol *tlbl = newiTempLabel (NULL);
10096               emit2 ("bit %d, a", len - 1);
10097               emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
10098               emit2 ("or a, !immedbyte", (unsigned char) (0xff << len));
10099               emitLabel (tlbl);
10100             }
10101           regalloc_dry_run_cost += 7;
10102         }
10103     }
10104 }
10105 
10106 /*-----------------------------------------------------------------*/
10107 /* genUnpackBits - generates code for unpacking bits               */
10108 /*-----------------------------------------------------------------*/
10109 static void
genUnpackBits(operand * result,int pair,const iCode * ic)10110 genUnpackBits (operand * result, int pair, const iCode *ic)
10111 {
10112   int offset = 0;               /* result byte offset */
10113   int rsize;                    /* result size */
10114   int rlen = 0;                 /* remaining bit-field length */
10115   sym_link *etype;              /* bit-field type information */
10116   unsigned blen;                /* bit-field length */
10117   unsigned bstr;                /* bit-field starting bit within byte */
10118   unsigned int pairincrement = 0;
10119 
10120   emitDebug ("; genUnpackBits");
10121 
10122   etype = getSpec (operandType (result));
10123   rsize = getSize (operandType (result));
10124   blen = SPEC_BLEN (etype);
10125   bstr = SPEC_BSTR (etype);
10126 
10127   /* If the bit-field length is less than a byte */
10128   if (blen < 8)
10129     {
10130       emit2 ("ld a, !*pair", _pairs[pair].name);
10131       regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
10132       AccRol (8 - bstr);
10133       unpackMaskA (etype, blen);
10134       cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10135       goto finish;
10136     }
10137 
10138   /* TODO: what if pair == PAIR_DE ? */
10139   if (getPairId (AOP (result)) == PAIR_HL ||
10140       AOP_TYPE (result) == AOP_REG && rsize >= 2 && (AOP (result)->aopu.aop_reg[0]->rIdx == L_IDX
10141           || AOP (result)->aopu.aop_reg[0]->rIdx == H_IDX))
10142     {
10143       wassertl (rsize == 2, "HL must be of size 2");
10144       emit2 ("ld a, !*hl");
10145       emit2 ("inc hl");
10146       if (AOP_TYPE (result) != AOP_REG || AOP (result)->aopu.aop_reg[0]->rIdx != H_IDX)
10147         {
10148           emit2 ("ld h, !*hl");
10149           cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10150           emit2 ("ld a, h");
10151         }
10152       else
10153         {
10154           emit2 ("ld l, !*hl");
10155           cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10156           emit2 ("ld a, l");
10157         }
10158       regalloc_dry_run_cost += 5;
10159       unpackMaskA (etype, blen - 8);
10160       cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10161       regalloc_dry_run_cost += 1;
10162       spillPair (PAIR_HL);
10163       return;
10164     }
10165 
10166   /* Bit field did not fit in a byte. Copy all
10167      but the partial byte at the end.  */
10168   for (rlen = blen; rlen >= 8; rlen -= 8)
10169     {
10170       emit2 ("ld a, !*pair", _pairs[pair].name);
10171       regalloc_dry_run_cost += 1;
10172       cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10173       if (rlen > 8)
10174         {
10175           emit2 ("inc %s", _pairs[pair].name);
10176           regalloc_dry_run_cost += 1;
10177           _G.pairs[pair].offset++;
10178           pairincrement++;
10179         }
10180     }
10181 
10182   /* Handle the partial byte at the end */
10183   if (rlen)
10184     {
10185       emit2 ("ld a, !*pair", _pairs[pair].name);
10186       regalloc_dry_run_cost++;
10187       unpackMaskA (etype, rlen);
10188       cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
10189     }
10190 
10191 finish:
10192   if (!isPairDead(pair, ic))
10193     while (pairincrement)
10194       {
10195         emit2 ("dec %s", _pairs[pair].name);
10196         regalloc_dry_run_cost += 1;
10197         pairincrement--;
10198         _G.pairs[pair].offset--;
10199       }
10200 
10201   if (offset < rsize)
10202     {
10203       asmop *source;
10204 
10205       if (SPEC_USIGN (etype))
10206         source = ASMOP_ZERO;
10207       else
10208         {
10209           /* signed bit-field: sign extension with 0x00 or 0xff */
10210           emit3 (A_RLA, 0, 0);
10211           emit3 (A_SBC, ASMOP_A, ASMOP_A);
10212           source = ASMOP_A;
10213         }
10214       rsize -= offset;
10215       while (rsize--)
10216         cheapMove (AOP (result), offset++, source, 0, true);
10217     }
10218 }
10219 
10220 static void
_moveFrom_tpair_(asmop * aop,int offset,PAIR_ID pair)10221 _moveFrom_tpair_ (asmop * aop, int offset, PAIR_ID pair)
10222 {
10223   emitDebug ("; _moveFrom_tpair_()");
10224   if (pair == PAIR_HL && aop->type == AOP_REG)
10225     {
10226       if (!regalloc_dry_run)
10227         aopPut (aop, "!*hl", offset);
10228       regalloc_dry_run_cost += ld_cost (aop, ASMOP_A);
10229     }
10230   else
10231     {
10232       emit2 ("ld a, !*pair", _pairs[pair].name);
10233       regalloc_dry_run_cost += 1;
10234       cheapMove (aop, offset, ASMOP_A, 0, true);
10235     }
10236 }
10237 
offsetPair(PAIR_ID pair,PAIR_ID extrapair,bool save_extrapair,int val)10238 static void offsetPair (PAIR_ID pair, PAIR_ID extrapair, bool save_extrapair, int val)
10239 {
10240   if (abs (val) < (save_extrapair ? 6 : 4) || pair != PAIR_HL && pair != PAIR_IY && pair != PAIR_IX)
10241     {
10242       while (val)
10243         {
10244           emit2 (val > 0 ? "inc %s" : "dec %s", _pairs[pair].name);
10245           if (val > 0)
10246             val--;
10247           else
10248             val++;
10249           regalloc_dry_run_cost++;
10250         }
10251     }
10252   else
10253     {
10254       if (save_extrapair)
10255         _push (extrapair);
10256       emit2 ("ld %s, !immedword", _pairs[extrapair].name, val);
10257       emit2 ("add %s, %s", _pairs[pair].name, _pairs[extrapair].name);
10258       regalloc_dry_run_cost += (pair == PAIR_HL ? 4 : 5);
10259       if (save_extrapair)
10260         _pop (extrapair);
10261     }
10262 }
10263 
10264 /*-----------------------------------------------------------------*/
10265 /* genPointerGet - generate code for pointer get                   */
10266 /*-----------------------------------------------------------------*/
10267 static void
genPointerGet(const iCode * ic)10268 genPointerGet (const iCode *ic)
10269 {
10270   operand *left, *right, *result;
10271   int size, offset, rightval;
10272   int pair = PAIR_HL, extrapair;
10273   sym_link *retype;
10274   bool pushed_pair = FALSE;
10275   bool pushed_a = FALSE;
10276   bool surviving_a = !options.oldralloc && bitVectBitValue (ic->rSurv, A_IDX);
10277   bool rightval_in_range;
10278 
10279   left = IC_LEFT (ic);
10280   right = IC_RIGHT (ic);
10281   result = IC_RESULT (ic);
10282   retype = getSpec (operandType (result));
10283 
10284   aopOp (left, ic, FALSE, FALSE);
10285   aopOp (result, ic, FALSE, FALSE);
10286   size = AOP_SIZE (result);
10287 
10288   /* Historically GET_VALUE_AT_ADDRESS didn't have a right operand */
10289   wassertl (right, "GET_VALUE_AT_ADDRESS without right operand");
10290   wassertl (IS_OP_LITERAL (IC_RIGHT (ic)), "GET_VALUE_AT_ADDRESS with non-literal right operand");
10291   rightval = (int)operandLitValue (right);
10292   rightval_in_range = (rightval >= -128 && rightval + size - 1 < 127);
10293   if (IS_GB)
10294     wassert (!rightval);
10295 
10296   if (IS_GB && left->aop->type == AOP_STK) // Try to avoid (hl) to hl copy, which requires 3 instructions and free a.
10297     pair = PAIR_DE;
10298   if ((IS_GB || IY_RESERVED) && requiresHL (AOP (result)) && size > 1 && AOP_TYPE (result) != AOP_REG)
10299     pair = PAIR_DE;
10300 
10301   if (AOP_TYPE (left) == AOP_IMMD && size == 1 && aopInReg (result->aop, 0, A_IDX) && !IS_BITVAR (retype))
10302     {
10303       emit2 ("ld a, (%s)", aopGetLitWordLong (AOP (left), rightval, TRUE));
10304       regalloc_dry_run_cost += 3;
10305       goto release;
10306     }
10307   else if (!IS_GB && AOP_TYPE (left) == AOP_IMMD && isPair (AOP (result)) && !IS_BITVAR (retype))
10308     {
10309       PAIR_ID pair = getPairId (AOP (result));
10310       emit2 ("ld %s, (%s)", _pairs[pair].name, aopGetLitWordLong (AOP (left), rightval, TRUE));
10311       regalloc_dry_run_cost += (pair == PAIR_HL ? 3 : 4);
10312       goto release;
10313     }
10314   else if (!IS_GB && AOP_TYPE (left) == AOP_IMMD && getPartPairId (AOP (result), 0) != PAIR_INVALID && getPartPairId (AOP (result), 2) != PAIR_INVALID)
10315    {
10316       PAIR_ID pair;
10317       pair = getPartPairId (AOP (result), 0);
10318       emit2 ("ld %s, (%s)", _pairs[pair].name, aopGetLitWordLong (AOP (left), rightval, TRUE));
10319       regalloc_dry_run_cost += (pair == PAIR_HL ? 3 : 4);
10320       pair = getPartPairId (AOP (result), 2);
10321       emit2 ("ld %s, (%s)", _pairs[pair].name, aopGetLitWordLong (AOP (left), rightval + 2, TRUE));
10322       regalloc_dry_run_cost += (pair == PAIR_HL ? 3 : 4);
10323       goto release;
10324    }
10325 
10326   if (isPair (AOP (left)) && size == 1 && !IS_BITVAR (retype) && !rightval)
10327     {
10328       /* Just do it */
10329       if (isPtrPair (AOP (left)))
10330         {
10331           if (!regalloc_dry_run)        // Todo: More exact cost.
10332             {
10333               struct dbuf_s dbuf;
10334 
10335               dbuf_init (&dbuf, 128);
10336               dbuf_tprintf (&dbuf, "!*pair", getPairName (AOP (left)));
10337               aopPut (AOP (result), dbuf_c_str (&dbuf), 0);
10338               dbuf_destroy (&dbuf);
10339             }
10340           regalloc_dry_run_cost += ld_cost (AOP (result), ASMOP_A);
10341         }
10342       else
10343         {
10344           if (surviving_a && !pushed_a)
10345             _push (PAIR_AF), pushed_a = TRUE;
10346           emit2 ("ld a, !*pair", getPairName (AOP (left)));
10347           regalloc_dry_run_cost += (getPairId (AOP (left)) == PAIR_IY ? 3 : 1);
10348           cheapMove (AOP (result), 0, ASMOP_A, 0, true);
10349         }
10350 
10351       goto release;
10352     }
10353 
10354   if (getPairId (AOP (left)) == PAIR_IY && !IS_BITVAR (retype) && rightval_in_range)
10355     {
10356       offset = 0;
10357 
10358       if ((IS_RAB || IS_TLCS90) && getPartPairId (AOP (result), 0) == PAIR_HL)
10359         {
10360           emit2 ("ld hl, %d (iy)", rightval);
10361           regalloc_dry_run_cost += 3;
10362           offset = 2;
10363           size -= 2;
10364         }
10365       else if (IS_EZ80_Z80 && getPartPairId (AOP (result), 0) != PAIR_INVALID)
10366         {
10367           emit2 ("ld %s, %d (iy)", _pairs[getPartPairId (AOP (result), 0)].name, rightval);
10368           regalloc_dry_run_cost += 3;
10369           offset = 2;
10370           size -= 2;
10371         }
10372 
10373       if (!size)
10374         goto release;
10375 
10376       /* Just do it */
10377       if (surviving_a && !pushed_a)
10378         _push (PAIR_AF), pushed_a = TRUE;
10379 
10380       while (size--)
10381         {
10382           if (!regalloc_dry_run)
10383             {
10384               struct dbuf_s dbuf;
10385 
10386               dbuf_init (&dbuf, 128);
10387               dbuf_tprintf (&dbuf, "!*iyx", rightval + offset);
10388               aopPut (AOP (result), dbuf_c_str (&dbuf), offset);
10389               dbuf_destroy (&dbuf);
10390             }
10391           regalloc_dry_run_cost += ld_cost (AOP (result), ASMOP_A) + 2; // Todo: More exact cost.
10392           offset++;
10393         }
10394 
10395       goto release;
10396     }
10397 
10398   /* Using ldir is cheapest for large memory-to-memory transfers. */
10399   if (!IS_GB && (AOP_TYPE (result) == AOP_STK || AOP_TYPE (result) == AOP_EXSTK) && size > 2 && (!rightval || AOP_TYPE (left) == AOP_IMMD))
10400     {
10401       int fp_offset, sp_offset;
10402 
10403       if(!isPairDead (PAIR_HL, ic))
10404         _push (PAIR_HL);
10405       if(!isPairDead (PAIR_DE, ic))
10406         _push (PAIR_DE);
10407       if(!isPairDead (PAIR_BC, ic))
10408         _push (PAIR_BC);
10409 
10410       if (!rightval)
10411         fetchPair (PAIR_DE, AOP (left));
10412       else
10413         {
10414           emit2 ("ld de, %s", aopGetLitWordLong (AOP (left), rightval, TRUE));
10415           regalloc_dry_run_cost += 3;
10416         }
10417 
10418       fp_offset = AOP (result)->aopu.aop_stk + (AOP (result)->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
10419       sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
10420       emit2 ("ld hl, !immedword", sp_offset);
10421       emit2 ("add hl, sp");
10422       emit2 ("ex de, hl");
10423       emit2 ("ld bc, !immedword", size);
10424       emit2 ("ldir");
10425       regalloc_dry_run_cost += 10;
10426       spillPair (PAIR_HL);
10427       spillPair (PAIR_DE);
10428       spillPair (PAIR_BC);
10429 
10430       if(!isPairDead (PAIR_BC, ic))
10431         _pop (PAIR_BC);
10432       if(!isPairDead (PAIR_DE, ic))
10433         _pop (PAIR_DE);
10434       if(!isPairDead (PAIR_HL, ic))
10435         _pop (PAIR_HL);
10436 
10437       goto release;
10438     }
10439 
10440   extrapair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
10441 
10442   /* For now we always load into temp pair */
10443   /* if this is rematerializable */
10444   if (!IS_GB && (getPairId (AOP (left)) == PAIR_BC || getPairId (AOP (left)) == PAIR_DE) && AOP_TYPE (result) == AOP_STK && !rightval
10445       || getPairId (AOP (left)) == PAIR_IY && SPEC_BLEN (getSpec (operandType (result))) < 8 && rightval_in_range)
10446     pair = getPairId (AOP (left));
10447   else
10448     {
10449       if (!isPairDead (pair, ic) && size > 1 && (getPairId (AOP (left)) != pair || rightval || IS_BITVAR (retype) || size > 2)) // For simple cases, restoring via dec is cheaper than push / pop.
10450         _push (pair), pushed_pair = TRUE;
10451       if (AOP_TYPE(left) == AOP_IMMD)
10452         {
10453           emit2 ("ld %s, %s", _pairs[pair].name, aopGetLitWordLong (AOP (left), rightval, TRUE));
10454           spillPair (pair);
10455           regalloc_dry_run_cost += 3;
10456           rightval = 0;
10457         }
10458       else
10459         fetchPair (pair, AOP (left));
10460     }
10461 
10462   /* if bit then unpack */
10463   if (IS_BITVAR (retype))
10464     {
10465       offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
10466       genUnpackBits (result, pair, ic);
10467       if (rightval)
10468         spillPair (pair);
10469 
10470       goto release;
10471     }
10472 
10473  if (isPair (AOP (result)) && IS_EZ80_Z80 && getPairId (AOP (left)) == PAIR_HL && !IS_BITVAR (retype) && !rightval)
10474    {
10475      emit2 ("ld %s, (hl)", _pairs[getPairId (AOP (result))].name);
10476      regalloc_dry_run_cost += 2;
10477      goto release;
10478    }
10479  else if (getPairId (AOP (result)) == PAIR_HL || size == 2 && (aopInReg (result->aop, 0, L_IDX) || aopInReg (result->aop, 0, H_IDX)))
10480     {
10481       wassertl (size == 2, "HL must be of size 2");
10482       if (IS_RAB && getPairId (AOP (result)) == PAIR_HL && rightval_in_range)
10483         {
10484           emit2 ("ld hl, %d (hl)", rightval);
10485           regalloc_dry_run_cost += 3;
10486         }
10487       else if (IS_EZ80_Z80 && getPairId (AOP (result)) == PAIR_HL && !rightval)
10488         {
10489           emit2 ("ld hl, (hl)");
10490           regalloc_dry_run_cost += 2;
10491         }
10492       else if (aopInReg (result->aop, 1, A_IDX))
10493         {
10494           offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval + 1);
10495           emit2 ("ld a, !*hl");
10496           emit2 ("dec hl");
10497           if (!regalloc_dry_run)
10498             aopPut (AOP (result), "!*hl", 0);
10499           regalloc_dry_run_cost += 3;
10500         }
10501       else
10502         {
10503           if (surviving_a && !pushed_a)
10504             _push (PAIR_AF), pushed_a = TRUE;
10505           offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
10506           emit2 ("ld a, !*hl");
10507           emit2 ("inc hl");
10508           if (!regalloc_dry_run)
10509             aopPut (AOP (result), "!*hl", 1);
10510           regalloc_dry_run_cost += 3;
10511           cheapMove (result->aop, 0, ASMOP_A, 0, true);
10512         }
10513       spillPair (PAIR_HL);
10514       goto release;
10515     }
10516 
10517   offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
10518 
10519   if (pair == PAIR_HL
10520            || (!IS_GB && (getPairId (AOP (left)) == PAIR_BC || getPairId (AOP (left)) == PAIR_DE)
10521                && AOP_TYPE (result) == AOP_STK))
10522     {
10523       size = AOP_SIZE (result);
10524       offset = 0;
10525       int last_offset = 0;
10526 
10527       /* might use ld a,(hl) followed by ld d (iy),a */
10528       if ((AOP_TYPE (result) == AOP_EXSTK || AOP_TYPE (result) == AOP_STK) && surviving_a && !pushed_a)
10529         _push (PAIR_AF), pushed_a = TRUE;
10530 
10531       if (size >= 2 && pair == PAIR_HL && AOP_TYPE (result) == AOP_REG)
10532         {
10533           int i, l = -10, h = -10, r;
10534           for (i = 0; i < size; i++)
10535             {
10536               if (AOP (result)->aopu.aop_reg[i]->rIdx == L_IDX)
10537                 l = i;
10538               else if (AOP (result)->aopu.aop_reg[i]->rIdx == H_IDX)
10539                 h = i;
10540             }
10541 
10542           if (l == -10 && h >= 0 && h < size - 1 || h == -10 && l >= 0 && l < size - 1) // One byte of result somewehere in hl. Just assign it last.
10543             {
10544               r = (l == -10 ? h : l);
10545 
10546               while (offset < size)
10547                 {
10548                   if (offset != r)
10549                     _moveFrom_tpair_ (AOP (result), offset, pair);
10550 
10551                   if (offset < size)
10552                     {
10553                       offset++;
10554                       emit2 ("inc %s", _pairs[pair].name);
10555                       regalloc_dry_run_cost += 1;
10556                       _G.pairs[pair].offset++;
10557                     }
10558                 }
10559 
10560               for (size = offset; size != r; size--)
10561                 {
10562                   emit2 ("dec %s", _pairs[pair].name);
10563                   regalloc_dry_run_cost += 1;
10564                 }
10565 
10566               _moveFrom_tpair_ (AOP (result), r, pair);
10567 
10568               // No fixup since result uses HL.
10569               spillPair (pair);
10570               goto release;
10571             }
10572           else if (l >= 0 && h >= 0)    // Two bytes of result somewehere in hl. Assign it last and use a for caching.
10573             {
10574               while (offset < size)
10575                 {
10576                   last_offset = offset;
10577 
10578                   if (IS_EZ80_Z80 && offset != l && offset != h && getPairId_o (result->aop, offset) != PAIR_INVALID)
10579                     {
10580                       emit2 ("ld %s, !*hl", _pairs[getPairId_o (result->aop, offset)].name);
10581                       regalloc_dry_run_cost += 2;
10582                       offset += 2;
10583                       if (offset < size)
10584                         {
10585                           emit2 ("inc %s", _pairs[pair].name);
10586                           emit2 ("inc %s", _pairs[pair].name);
10587                           regalloc_dry_run_cost += 2;
10588                           _G.pairs[pair].offset += 2;
10589                         }
10590                       continue;
10591                     }
10592 
10593                   if (offset != l && offset != h)
10594                     _moveFrom_tpair_ (AOP (result), offset, pair);
10595                   offset++;
10596 
10597                   if (offset < size)
10598                     {
10599                       emit2 ("inc %s", _pairs[pair].name);
10600                       regalloc_dry_run_cost += 1;
10601                       _G.pairs[pair].offset++;
10602                     }
10603                 }
10604 
10605               r = (l > h ? l : h);
10606               for (size = last_offset; size != r; size--)
10607                 {
10608                   emit2 ("dec %s", _pairs[pair].name);
10609                   regalloc_dry_run_cost += 1;
10610                 }
10611               if ((surviving_a || result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < r) && !pushed_a)
10612                 _push (PAIR_AF), pushed_a = TRUE;
10613               _moveFrom_tpair_ (ASMOP_A, 0, pair);
10614 
10615               r = (l < h ? l : h);
10616               for (; size != r; size--)
10617                 {
10618                   emit2 ("dec %s", _pairs[pair].name);
10619                   regalloc_dry_run_cost += 1;
10620                 }
10621               _moveFrom_tpair_ (AOP (result), r, pair);
10622 
10623               r = (l > h ? l : h);
10624               cheapMove (result->aop, r, ASMOP_A, 0, true);
10625 
10626               // No fixup since result uses HL.
10627               spillPair (pair);
10628               goto release;
10629             }
10630         }
10631 
10632       while (offset < size)
10633         {
10634           last_offset = offset;
10635 
10636           if (IS_EZ80_Z80 && getPairId_o (result->aop, offset) != PAIR_INVALID)
10637             {
10638               emit2 ("ld %s, !*hl", _pairs[getPairId_o (result->aop, offset)].name);
10639               regalloc_dry_run_cost += 2;
10640               offset += 2;
10641               if (offset < size)
10642                 {
10643                   emit2 ("inc %s", _pairs[pair].name);
10644                   emit2 ("inc %s", _pairs[pair].name);
10645                   regalloc_dry_run_cost += 2;
10646                   _G.pairs[pair].offset += 2;
10647                 }
10648               continue;
10649             }
10650 
10651           _moveFrom_tpair_ (AOP (result), offset++, pair);
10652 
10653           if (offset < size)
10654             {
10655               emit2 ("inc %s", _pairs[pair].name);
10656               regalloc_dry_run_cost += 1;
10657               _G.pairs[pair].offset++;
10658             }
10659         }
10660       /* Fixup HL back down */
10661       if (getPairId (AOP (left)) == pair && !isPairDead (pair, ic) && !pushed_pair)
10662         while (last_offset --> 0)
10663           {
10664             emit2 ("dec %s", _pairs[pair].name);
10665             regalloc_dry_run_cost += 1;
10666             _G.pairs[pair].offset--;
10667           }
10668        else if (rightval || AOP_SIZE (result))
10669          spillPair (pair);
10670     }
10671   else
10672     {
10673       size = AOP_SIZE (result);
10674       offset = 0;
10675 
10676       for (offset = 0; offset < size;)
10677         {
10678           if (surviving_a && !pushed_a)
10679             _push (PAIR_AF), pushed_a = TRUE;
10680 
10681           /* PENDING: make this better */
10682           if ((pair == PAIR_HL) && AOP_TYPE (result) == AOP_REG)
10683             {
10684               if (!regalloc_dry_run)
10685                 aopPut (AOP (result), "!*hl", offset++);
10686               regalloc_dry_run_cost += ld_cost (AOP (result), ASMOP_A);
10687             }
10688           else
10689             {
10690               emit2 ("ld a,!*pair", _pairs[pair].name);
10691               regalloc_dry_run_cost += 1;
10692               cheapMove (result->aop, offset++, ASMOP_A, 0, true);
10693             }
10694           if (offset < size)
10695             {
10696               emit2 ("inc %s", _pairs[pair].name);
10697               regalloc_dry_run_cost += 1;
10698               _G.pairs[pair].offset++;
10699             }
10700         }
10701       if (rightval || AOP_SIZE (result))
10702          spillPair (pair);
10703     }
10704 
10705 release:
10706   if (pushed_a)
10707     _pop (PAIR_AF);
10708   if (pushed_pair)
10709     _pop (pair);
10710 
10711   freeAsmop (left, NULL);
10712   freeAsmop (result, NULL);
10713 }
10714 
10715 static bool
isRegOrLit(asmop * aop)10716 isRegOrLit (asmop * aop)
10717 {
10718   if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
10719     return true;
10720   return false;
10721 }
10722 
10723 
10724 /*-----------------------------------------------------------------*/
10725 /* genPackBits - generates code for packed bit storage             */
10726 /*-----------------------------------------------------------------*/
10727 static void
genPackBits(sym_link * etype,operand * right,int pair,const iCode * ic)10728 genPackBits (sym_link * etype, operand * right, int pair, const iCode * ic)
10729 {
10730   int offset = 0;               /* source byte offset */
10731   int pair_offset = 0;
10732   int rlen = 0;                 /* remaining bit-field length */
10733   unsigned blen;                /* bit-field length */
10734   unsigned bstr;                /* bit-field starting bit within byte */
10735   int litval;                   /* source literal value (if AOP_LIT) */
10736   unsigned char mask;           /* bitmask within current byte */
10737   int extraPair;                /* a tempory register */
10738   bool needPopExtra = 0;        /* need to restore original value of temp reg */
10739   unsigned int pairincrement = 0;
10740 
10741   emitDebug ("; genPackBits", "");
10742 
10743   blen = SPEC_BLEN (etype);
10744   bstr = SPEC_BSTR (etype);
10745 
10746   /* If the bit-field length is less than a byte */
10747   if (blen < 8)
10748     {
10749       mask = ((unsigned char) (0xFF << (blen + bstr)) | (unsigned char) (0xFF >> (8 - bstr)));
10750 
10751       if (AOP_TYPE (right) == AOP_LIT && blen == 1 && (pair == PAIR_HL || pair == PAIR_IX || pair == PAIR_IY))
10752         {
10753           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10754           emit2 (litval & 1 ? "set %d, !*pair" : "res %d, !*pair", bstr, _pairs[pair].name);
10755           regalloc_dry_run_cost = (pair == PAIR_IX || pair == PAIR_IY) ? 4 : 2;
10756           return;
10757         }
10758       else if (AOP_TYPE (right) == AOP_LIT)
10759         {
10760           /* Case with a bit-field length <8 and literal source */
10761           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10762           litval <<= bstr;
10763           litval &= (~mask) & 0xff;
10764           emit2 ("ld a, !*pair", _pairs[pair].name);
10765           regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
10766           if ((mask | litval) != 0xff)
10767             {
10768               emit2 ("and a, !immedbyte", mask);
10769               regalloc_dry_run_cost += 2;
10770             }
10771           if (litval)
10772             {
10773               emit2 ("or a, !immedbyte", litval);
10774               regalloc_dry_run_cost += 1;
10775             }
10776           emit2 ("ld !*pair,a", _pairs[pair].name);
10777           regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
10778           return;
10779         }
10780       else if (blen == 4 && bstr % 4 == 0 && pair == PAIR_HL && !aopInReg (right->aop, 0, A_IDX) && !requiresHL (right->aop) && (IS_Z80 || IS_Z180 || IS_EZ80_Z80))
10781         {
10782           emit2 (bstr ? "rld" : "rrd");
10783           regalloc_dry_run_cost += 2;
10784           cheapMove (ASMOP_A, 0, AOP (right), 0, true);
10785           emit2 (bstr ? "rrd" : "rld");
10786           regalloc_dry_run_cost += 2;
10787           return;
10788         }
10789       else
10790         {
10791           /* Case with a bit-field length <8 and arbitrary source */
10792           cheapMove (ASMOP_A, 0, AOP (right), 0, true);
10793           /* shift and mask source value */
10794           if (blen + bstr == 8)
10795             AccLsh (bstr);
10796           else
10797             {
10798               AccRol (bstr);
10799               emit2 ("and a, !immedbyte", (~mask) & 0xff);
10800               regalloc_dry_run_cost += 2;
10801             }
10802 
10803           extraPair = getFreePairId (ic);
10804           if (extraPair == PAIR_INVALID)
10805             {
10806               if (pair != PAIR_HL)
10807                 extraPair = PAIR_HL;
10808               else
10809                 {
10810                   extraPair = PAIR_BC;
10811                   if (getPairId (AOP (right)) != PAIR_BC || !isLastUse (ic, right))
10812                     {
10813                       _push (extraPair);
10814                       needPopExtra = 1;
10815                     }
10816                 }
10817             }
10818           emit2 ("ld %s, a", _pairs[extraPair].l);
10819           spillPair (extraPair);
10820           regalloc_dry_run_cost += 1;
10821           emit2 ("ld a, !*pair", _pairs[pair].name);
10822           regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
10823 
10824           emit2 ("and a, !immedbyte", mask);
10825           regalloc_dry_run_cost += 2;
10826           emit2 ("or a, %s", _pairs[extraPair].l);
10827           regalloc_dry_run_cost += 1;
10828           emit2 ("ld !*pair, a", _pairs[pair].name);
10829           regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
10830           if (needPopExtra)
10831             _pop (extraPair);
10832           return;
10833         }
10834     }
10835 
10836   /* Bit length is greater than 7 bits. In this case, copy  */
10837   /* all except the partial byte at the end                 */
10838   for (rlen = blen; rlen >= 8; rlen -= 8)
10839     {
10840       cheapMove (ASMOP_A, 0, AOP (right), offset++, true);
10841       if (pair == PAIR_IX || pair == PAIR_IY)
10842         {
10843           emit2 ("ld %d !*pair,a", pair_offset, _pairs[pair].name);
10844           regalloc_dry_run_cost += 3;
10845         }
10846       else
10847         {
10848           emit2 ("ld !*pair,a", _pairs[pair].name);
10849           regalloc_dry_run_cost += 1;
10850         }
10851       if (rlen > 8 && pair != PAIR_IX && pair != PAIR_IY)
10852         {
10853           emit2 ("inc %s", _pairs[pair].name);
10854           regalloc_dry_run_cost += 1;
10855           pairincrement++;
10856           _G.pairs[pair].offset++;
10857         }
10858       else
10859         pair_offset++;
10860     }
10861 
10862   /* If there was a partial byte at the end */
10863   if (rlen)
10864     {
10865       mask = (((unsigned char) - 1 << rlen) & 0xff);
10866 
10867       if (AOP_TYPE (right) == AOP_LIT)
10868         {
10869           /* Case with partial byte and literal source */
10870           litval = (int) ulFromVal (AOP (right)->aopu.aop_lit);
10871           litval >>= (blen - rlen);
10872           litval &= (~mask) & 0xff;
10873 
10874           if (pair == PAIR_IX || pair == PAIR_IY)
10875             {
10876               emit2 ("ld a, %d !*pair", pair_offset, _pairs[pair].name);
10877               regalloc_dry_run_cost += 3;
10878             }
10879           else
10880             {
10881               emit2 ("ld a, !*pair", _pairs[pair].name);
10882               regalloc_dry_run_cost += 1;
10883             }
10884 
10885           if ((mask | litval) != 0xff)
10886             emit2 ("and a, !immedbyte", mask);
10887           if (litval)
10888             emit2 ("or a, !immedbyte", litval);
10889         }
10890       else
10891         {
10892           /* Case with partial byte and arbitrary source */
10893           cheapMove (ASMOP_A, 0, AOP (right), offset++, true);
10894           emit2 ("and a, !immedbyte", (~mask) & 0xff);
10895           regalloc_dry_run_cost += 2;
10896 
10897           extraPair = getFreePairId (ic);
10898           if (extraPair == PAIR_INVALID)
10899             {
10900               if (pair != PAIR_HL)
10901                 extraPair = PAIR_HL;
10902               else
10903                 {
10904                   extraPair = PAIR_BC;
10905                   if (getPairId (AOP (right)) != PAIR_BC || !isLastUse (ic, right))
10906                     {
10907                       _push (extraPair);
10908                       needPopExtra = 1;
10909                     }
10910                 }
10911             }
10912 
10913           emit2 ("ld %s,a", _pairs[extraPair].l);
10914           spillPair (extraPair);
10915           regalloc_dry_run_cost += 1;
10916 
10917           if (pair == PAIR_IX || pair == PAIR_IY)
10918             {
10919               emit2 ("ld a, %d !*pair", pair_offset, _pairs[pair].name);
10920               regalloc_dry_run_cost += 3;
10921             }
10922           else
10923             {
10924               emit2 ("ld a, !*pair", _pairs[pair].name);
10925               regalloc_dry_run_cost += 1;
10926             }
10927 
10928           emit2 ("and a, !immedbyte", mask);
10929           regalloc_dry_run_cost += 2;
10930           emit2 ("or a, %s", _pairs[extraPair].l);
10931           regalloc_dry_run_cost += 1;
10932           if (needPopExtra)
10933             _pop (extraPair);
10934 
10935         }
10936       if (pair == PAIR_IX || pair == PAIR_IY)
10937         {
10938           emit2 ("ld %d !*pair, a", pair_offset, _pairs[pair].name);
10939           regalloc_dry_run_cost += 3;
10940         }
10941       else
10942         {
10943           emit2 ("ld !*pair, a", _pairs[pair].name);
10944           regalloc_dry_run_cost += 1;
10945         }
10946     }
10947   if (!isPairDead(pair, ic))
10948     while (pairincrement)
10949       {
10950         emit2 ("dec %s", _pairs[pair].name);
10951         regalloc_dry_run_cost += 1;
10952         pairincrement--;
10953         _G.pairs[pair].offset--;
10954       }
10955 }
10956 
10957 /*-----------------------------------------------------------------*/
10958 /* genPointerSet - stores the value into a pointer location        */
10959 /*-----------------------------------------------------------------*/
10960 static void
genPointerSet(iCode * ic)10961 genPointerSet (iCode *ic)
10962 {
10963   int size, offset = 0;
10964   int last_offset = 0;
10965   operand *right, *result;
10966   PAIR_ID pairId = PAIR_HL;
10967   bool isBitvar;
10968   sym_link *retype;
10969   sym_link *letype;
10970   bool pushed_a = FALSE;
10971   bool surviving_a = !options.oldralloc && bitVectBitValue (ic->rSurv, A_IDX);
10972 
10973   right = IC_RIGHT (ic);
10974   result = IC_RESULT (ic);
10975   retype = getSpec (operandType (right));
10976   letype = getSpec (operandType (result));
10977 
10978   aopOp (result, ic, FALSE, FALSE);
10979   aopOp (right, ic, FALSE, FALSE);
10980 
10981   if (IS_GB)
10982     pairId = isRegOrLit (AOP (right)) ? PAIR_HL : PAIR_DE;
10983   else if (IY_RESERVED)
10984     pairId = (isRegOrLit (AOP (right)) || AOP_TYPE (right) == AOP_STK) ? PAIR_HL : PAIR_DE;
10985   if (isPair (AOP (result)) && isPairDead (getPairId (AOP (result)), ic))
10986     pairId = getPairId (AOP (result));
10987 
10988   size = AOP_SIZE (right);
10989 
10990   isBitvar = IS_BITVAR (retype) || IS_BITVAR (letype);
10991   emitDebug ("; isBitvar = %d", isBitvar);
10992 
10993   /* Handle the exceptions first */
10994   if (isPair (AOP (result)) && size == 1 && !isBitvar)
10995     {
10996       /* Just do it */
10997       const char *pair = getPairName (AOP (result));
10998       if (canAssignToPtr3 (AOP (right)) && isPtr (pair))        // Todo: correct cost for pair iy.
10999         {
11000           if (!regalloc_dry_run)
11001             emit2 ("ld !*pair, %s", pair, aopGet (AOP (right), 0, FALSE));
11002           regalloc_dry_run_cost += ld_cost (ASMOP_A, AOP (right)) + (getPairId (AOP (result)) != PAIR_IY ? 0 : 2);
11003         }
11004       else
11005         {
11006           if (surviving_a && !pushed_a && !aopInReg (right->aop, 0, A_IDX))
11007             _push (PAIR_AF), pushed_a = TRUE;
11008           if (AOP_TYPE (right) == AOP_LIT && byteOfVal (AOP (right)->aopu.aop_lit, offset) == 0x00)
11009             emit3 (A_XOR, ASMOP_A, ASMOP_A);
11010           else
11011             cheapMove (ASMOP_A, 0, AOP (right), 0, true);
11012           emit2 ("ld !*pair, a", pair);
11013           regalloc_dry_run_cost += (getPairId (AOP (result)) != PAIR_IY ? 1 : 3);
11014         }
11015       goto release;
11016     }
11017 
11018   /* Using ldir is cheapest for large memory-to-memory transfers. */
11019   if (!IS_GB && (AOP_TYPE (right) == AOP_STK || AOP_TYPE (right) == AOP_EXSTK) && size > 2)
11020     {
11021       int fp_offset, sp_offset;
11022 
11023       if(!isPairDead (PAIR_DE, ic))
11024         _push (PAIR_DE);
11025       if(!isPairDead (PAIR_BC, ic))
11026         _push (PAIR_BC);
11027       if(!isPairDead (PAIR_HL, ic))
11028         _push (PAIR_HL);
11029 
11030       fetchPair (PAIR_DE, AOP (result));
11031 
11032       fp_offset = AOP (right)->aopu.aop_stk + (AOP (right)->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
11033       sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
11034       emit2 ("ld hl, !immedword", sp_offset);
11035       emit2 ("add hl, sp");
11036       emit2 ("ld bc, !immedword", size);
11037       emit2 ("ldir");
11038       regalloc_dry_run_cost += 9;
11039 
11040       if(!isPairDead (PAIR_HL, ic))
11041         _pop (PAIR_HL);
11042       if(!isPairDead (PAIR_BC, ic))
11043         _pop (PAIR_BC);
11044       if(!isPairDead (PAIR_DE, ic))
11045         _pop (PAIR_DE);
11046       goto release;
11047     }
11048 
11049   if (getPairId (AOP (result)) == PAIR_IY && !isBitvar)
11050     {
11051       /* Just do it */
11052       while (size--)
11053         {
11054           if (canAssignToPtr3 (AOP (right)))
11055             {
11056               if (!regalloc_dry_run)
11057                 emit2 ("ld !*iyx, %s", offset, aopGet (AOP (right), offset, FALSE));
11058               regalloc_dry_run_cost += 3;       // Todo: More exact cost here!
11059             }
11060           else
11061             {
11062               cheapMove (ASMOP_A, 0, AOP (right), offset, true);
11063               emit2 ("ld !*iyx, a", offset);
11064               regalloc_dry_run_cost += 3;
11065             }
11066           offset++;
11067         }
11068       goto release;
11069     }
11070   else if (getPairId (result->aop) == PAIR_HL && !isPairDead (PAIR_HL, ic) && !isBitvar)
11071     {
11072       while (offset < size)
11073         {
11074           last_offset = offset;
11075 
11076           if (IS_EZ80_Z80 && offset + 1 < size && getPairId_o (right->aop, offset) != PAIR_INVALID)
11077             {
11078               emit2 ("ld !*pair, %s", _pairs[PAIR_HL].name, _pairs[getPairId_o (right->aop, offset)].name);
11079               regalloc_dry_run_cost += 2;
11080               offset += 2;
11081 
11082               if (offset < size)
11083                 {
11084                   emit2 ("inc %s", _pairs[PAIR_HL].name);
11085                   emit2 ("inc %s", _pairs[PAIR_HL].name);
11086                   regalloc_dry_run_cost += 2;
11087                   _G.pairs[PAIR_HL].offset++;
11088                 }
11089 
11090               continue;
11091             }
11092           else if (isRegOrLit (AOP (right)) && !IS_GB)
11093             {
11094               if (!regalloc_dry_run)
11095                 emit2 ("ld !*pair, %s", _pairs[PAIR_HL].name, aopGet (right->aop, offset, FALSE));
11096               regalloc_dry_run_cost += ld_cost (ASMOP_A, right->aop);
11097               offset++;
11098             }
11099           else
11100             {
11101               if (surviving_a && !pushed_a && (!aopInReg (right->aop, 0, A_IDX) || offset))
11102                 _push (PAIR_AF), pushed_a = TRUE;
11103               cheapMove (ASMOP_A, 0, right->aop, offset, true);
11104               emit2 ("ld !*pair, a", _pairs[PAIR_HL].name);
11105               regalloc_dry_run_cost += 1;
11106               offset++;
11107             }
11108 
11109           if (offset < size)
11110             {
11111               emit2 ("inc %s", _pairs[PAIR_HL].name);
11112               regalloc_dry_run_cost += 1;
11113               _G.pairs[PAIR_HL].offset++;
11114             }
11115         }
11116 
11117       /* Fixup HL back down */
11118       while (last_offset --> 0)
11119         {
11120           emit2 ("dec %s", _pairs[PAIR_HL].name);
11121           regalloc_dry_run_cost += 1;
11122         }
11123       goto release;
11124     }
11125 
11126   if (!IS_GB && !isBitvar && isLitWord (AOP (result)) && size == 2 && offset == 0 &&
11127       (AOP_TYPE (right) == AOP_REG && getPairId (AOP (right)) != PAIR_INVALID || isLitWord (AOP (right))))
11128     {
11129       if (isLitWord (AOP (right)))
11130         {
11131           pairId = PAIR_HL;
11132           fetchPairLong (pairId, AOP (right), ic, 0);
11133         }
11134       else
11135         pairId = getPairId (AOP (right));
11136       emit2 ("ld (%s), %s", aopGetLitWordLong (AOP (result), offset, FALSE), _pairs[pairId].name);
11137       regalloc_dry_run_cost += (pairId == PAIR_HL) ? 3 : 4;
11138       goto release;
11139     }
11140   if (!IS_GB && !isBitvar && isLitWord (AOP (result)) && size == 4 && offset == 0 &&
11141     (getPartPairId (AOP (right), 0) != PAIR_INVALID && getPartPairId (AOP (right), 2) != PAIR_INVALID || isLitWord (AOP (right))))
11142     {
11143       if (isLitWord (AOP (right)))
11144         {
11145           pairId = PAIR_HL;
11146           fetchPairLong (pairId, AOP (right), ic, 0);
11147         }
11148       else
11149         pairId = getPartPairId (AOP (right), 0);
11150       emit2 ("ld (%s), %s", aopGetLitWordLong (AOP (result), offset, FALSE), _pairs[pairId].name);
11151       regalloc_dry_run_cost += (pairId == PAIR_HL) ? 3 : 4;
11152       if (isLitWord (AOP (right)))
11153         {
11154           pairId = PAIR_HL;
11155           fetchPairLong (pairId, AOP (right), ic, 2);
11156         }
11157       else
11158         pairId = getPartPairId (AOP (right), 2);
11159       emit2 ("ld (%s+%d), %s", aopGetLitWordLong (AOP (result), offset, FALSE),2,  _pairs[pairId].name); // Handling of literal addresses is somewhat broken, use explicit offset as workaround.
11160       regalloc_dry_run_cost += (pairId == PAIR_HL) ? 3 : 4;
11161       goto release;
11162     }
11163 
11164   /* if the operand is already in dptr
11165      then we do nothing else we move the value to dptr */
11166   if (AOP_TYPE (result) != AOP_STR)
11167     {
11168       if (isBitvar && getPairId (AOP (result)) != PAIR_INVALID && (getPairId (AOP (result)) != PAIR_IY || SPEC_BLEN (IS_BITVAR (retype) ? retype : letype) < 8 || isPairDead (getPairId (AOP (result)), ic)))   /* Avoid destroying result by increments */
11169         pairId = getPairId (AOP (result));
11170       else
11171         fetchPairLong (pairId, AOP (result), ic, 0);
11172     }
11173   /* so hl now contains the address */
11174   /*freeAsmop (result, NULL, ic);*/
11175 
11176   /* if bit then unpack */
11177   if (isBitvar)
11178     {
11179       genPackBits ((IS_BITVAR (retype) ? retype : letype), right, pairId, ic);
11180       goto release;
11181     }
11182   else
11183     {
11184       bool zero_a = false;
11185 
11186       for (offset = 0; offset < size;)
11187         {
11188           last_offset = offset;
11189 
11190           if (IS_EZ80_Z80 && offset + 1 < size && pairId == PAIR_HL && getPairId_o (right->aop, offset) != PAIR_INVALID)
11191             {
11192               emit2 ("ld !*pair, %s", _pairs[pairId].name, _pairs[getPairId_o (right->aop, offset)].name);
11193               regalloc_dry_run_cost += 2;
11194               offset += 2;
11195 
11196               if (offset < size)
11197                 {
11198                   emit2 ("inc %s", _pairs[pairId].name);
11199                   emit2 ("inc %s", _pairs[pairId].name);
11200                   regalloc_dry_run_cost += 2;
11201                   _G.pairs[pairId].offset++;
11202                 }
11203 
11204               continue;
11205             }
11206 
11207           if (!zero_a && offset + 1 < size && aopIsLitVal (right->aop, offset, 2, 0x0000) && !surviving_a)
11208             {
11209               emit2 ("xor a, a");
11210               regalloc_dry_run_cost++;
11211               zero_a = true;
11212             }
11213 
11214           if (aopIsLitVal (right->aop, offset, 1, 0x00) && zero_a)
11215             {
11216               emit2 ("ld !*pair, a", _pairs[pairId].name);
11217               regalloc_dry_run_cost++;
11218             }
11219           else if (isRegOrLit (right->aop) && pairId == PAIR_HL)
11220             {
11221               if (!regalloc_dry_run)
11222                 emit2 ("ld !*pair, %s", _pairs[pairId].name, aopGet (AOP (right), offset, FALSE));
11223               regalloc_dry_run_cost += ld_cost (ASMOP_A, AOP (right));
11224             }
11225           else
11226             {
11227               if (surviving_a && !pushed_a && (!aopInReg (right->aop, 0, A_IDX) || offset))
11228                 _push (PAIR_AF), pushed_a = TRUE;
11229               cheapMove (ASMOP_A, 0, AOP (right), offset, true);
11230               zero_a = false;
11231               emit2 ("ld !*pair, a", _pairs[pairId].name);
11232               regalloc_dry_run_cost += 1;
11233             }
11234           offset++;
11235 
11236           if (offset < size)
11237             {
11238               emit2 ("inc %s", _pairs[pairId].name);
11239               regalloc_dry_run_cost += 1;
11240               _G.pairs[pairId].offset++;
11241             }
11242         }
11243       /* Restore operand partially in HL. */
11244       if (!isPairDead (pairId, ic) && AOP (result)->type == AOP_REG)
11245         {
11246           while(last_offset --> 0)
11247             {
11248               emit2 ("dec %s", _pairs[pairId].name);
11249               regalloc_dry_run_cost += 1;
11250               _G.pairs[pairId].offset--;
11251             }
11252           commitPair (AOP (result), pairId, ic, FALSE);
11253         }
11254     }
11255 release:
11256   if (pushed_a)
11257     _pop (PAIR_AF);
11258 
11259   freeAsmop (right, NULL);
11260   freeAsmop (result, NULL);
11261 }
11262 
11263 /*-----------------------------------------------------------------*/
11264 /* genIfx - generate code for Ifx statement                        */
11265 /*-----------------------------------------------------------------*/
11266 static void
genIfx(iCode * ic,iCode * popIc)11267 genIfx (iCode *ic, iCode *popIc)
11268 {
11269   operand *cond = IC_COND (ic);
11270   int isbit = 0;
11271 
11272   aopOp (cond, ic, FALSE, TRUE);
11273 
11274   /* get the value into acc */
11275   if (AOP_TYPE (cond) != AOP_CRY && !IS_BOOL (operandType (cond)))
11276     _toBoolean (cond, !popIc);
11277   /* Special case: Condition is bool */
11278   else if (IS_BOOL (operandType (cond)))
11279     {
11280       if (!regalloc_dry_run)
11281         {
11282           emit2 ("bit 0, %s", aopGet (AOP (cond), 0, FALSE));
11283           emit2 ("jp %s, !tlabel", IC_TRUE (ic) ? "NZ" : "Z", labelKey2num ((IC_TRUE (ic) ? IC_TRUE (ic) : IC_FALSE (ic))->key));
11284         }
11285       regalloc_dry_run_cost += (bit8_cost (AOP (cond)) + 3);
11286 
11287       freeAsmop (cond, NULL);
11288       if (!regalloc_dry_run)
11289         ic->generated = 1;
11290       return;
11291     }
11292   else
11293     isbit = 1;
11294   /* the result is now in the accumulator */
11295   freeAsmop (cond, NULL);
11296 
11297   /* if there was something to be popped then do it */
11298   if (popIc)
11299     genIpop (popIc);
11300 
11301   /* if the condition is  a bit variable */
11302   if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
11303     genIfxJump (ic, SPIL_LOC (cond)->rname);
11304   else if (isbit && !IS_ITEMP (cond))
11305     genIfxJump (ic, OP_SYMBOL (cond)->rname);
11306   else
11307     genIfxJump (ic, popIc ? "a" : "nz");
11308 
11309   if (!regalloc_dry_run)
11310     ic->generated = 1;
11311 }
11312 
11313 /*-----------------------------------------------------------------*/
11314 /* genAddrOf - generates code for address of                       */
11315 /*-----------------------------------------------------------------*/
11316 static void
genAddrOf(const iCode * ic)11317 genAddrOf (const iCode * ic)
11318 {
11319   symbol *sym;
11320   PAIR_ID pair;
11321   operand *right = IC_RIGHT (ic);
11322   wassert (IS_TRUE_SYMOP (IC_LEFT (ic)));
11323   wassert (right && IS_OP_LITERAL (IC_RIGHT (ic)));
11324   sym = OP_SYMBOL (IC_LEFT (ic));
11325   aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
11326 
11327   if (sym->onStack)
11328     {
11329       int fp_offset = sym->stack + (sym->stack > 0 ? _G.stack.param_offset : 0) + (int)operandLitValue (right);
11330       int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
11331       bool in_fp_range = !_G.omitFramePtr && (fp_offset >= -128 && fp_offset < 128);
11332 
11333       if (IS_EZ80_Z80 && in_fp_range && getPairId (IC_RESULT (ic)->aop) != PAIR_INVALID)
11334         pair = getPairId (IC_RESULT (ic)->aop);
11335       else
11336         pair = (getPairId (IC_RESULT (ic)->aop) == PAIR_IY) ? PAIR_IY : PAIR_HL;
11337       spillPair (pair);
11338       if (IS_EZ80_Z80 && in_fp_range)
11339         {
11340           emit2 ("lea %s, ix, #%d", _pairs[pair].name, fp_offset);
11341           regalloc_dry_run_cost += 3;
11342         }
11343       else
11344         setupPairFromSP (pair, sp_offset);
11345     }
11346   else
11347     {
11348       pair = getPairId (IC_RESULT (ic)->aop);
11349       if (pair == PAIR_INVALID)
11350         {
11351           pair = IS_GB ? PAIR_DE : PAIR_HL;
11352           spillPair (pair);
11353         }
11354       emit2 ("ld %s, !hashedstr+%ld", _pairs[pair].name, sym->rname, (long)(operandLitValue (right)));
11355       regalloc_dry_run_cost += (pair == PAIR_IY ? 4 : 3);
11356     }
11357 
11358   commitPair (IC_RESULT (ic)->aop, pair, ic, FALSE);
11359 
11360   freeAsmop (IC_RESULT (ic), NULL);
11361 }
11362 
11363 /*-----------------------------------------------------------------*/
11364 /* genAssign - generate code for assignment                        */
11365 /*-----------------------------------------------------------------*/
11366 static void
genAssign(const iCode * ic)11367 genAssign (const iCode *ic)
11368 {
11369   operand *result, *right;
11370   int size, offset;
11371 
11372   result = IC_RESULT (ic);
11373   right = IC_RIGHT (ic);
11374 
11375   /* Dont bother assigning if they are the same */
11376   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11377     return;
11378 
11379   aopOp (right, ic, FALSE, FALSE);
11380   aopOp (result, ic, TRUE, FALSE);
11381 
11382   /* if they are the same registers */
11383   if (sameRegs (AOP (right), AOP (result)))
11384     {
11385       emitDebug ("; (locations are the same)");
11386       goto release;
11387     }
11388 
11389   /* if the result is a bit */
11390   if (AOP_TYPE (result) == AOP_CRY)
11391     {
11392       wassertl (0, "Tried to assign to a bit");
11393     }
11394 
11395   /* general case */
11396   size = AOP_SIZE (result);
11397   offset = 0;
11398 
11399   if (isPair (AOP (result)))
11400     fetchPairLong (getPairId (AOP (result)), AOP (right), ic, LSB);
11401   else if (isPair (AOP (right)) && AOP_TYPE (result) == AOP_IY && size == 2)
11402     commitPair (AOP (result), getPairId (AOP (right)), ic, FALSE);
11403   else if (size == 2 && isPairDead (PAIR_HL, ic) &&
11404     (!IS_GB && (AOP_TYPE (right) == AOP_STK && !_G.omitFramePtr || AOP_TYPE (right) == AOP_IY || AOP_TYPE (right) == AOP_LIT) && AOP_TYPE (result) == AOP_IY || // Use ld (nn), hl
11405     !IS_GB && AOP_TYPE (right) == AOP_IY && (AOP_TYPE (result) == AOP_STK && !_G.omitFramePtr || AOP_TYPE (result) == AOP_IY) || // Use ld hl, (nn)
11406     !IS_GB && AOP_TYPE (right) == AOP_LIT && (AOP_TYPE(result) == AOP_STK || AOP_TYPE(result) == AOP_EXSTK) && (AOP(result)->aopu.aop_stk + offset + _G.stack.offset + (AOP(result)->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) + _G.stack.pushed) == 0 || // Use ex (sp), hl
11407     (IS_RAB || IS_TLCS90) && (AOP_TYPE(result) == AOP_STK || AOP_TYPE(result) == AOP_EXSTK) && (AOP_TYPE(right) == AOP_LIT || AOP_TYPE (right) == AOP_IMMD))) // Use ld d(sp), hl
11408     {
11409       fetchPair (PAIR_HL, AOP (right));
11410       commitPair (AOP (result), PAIR_HL, ic, FALSE);
11411     }
11412   else if (size == 2 && getPairId (AOP (right)) != PAIR_INVALID && getPairId (AOP (right)) != PAIR_IY && AOP_TYPE (result) != AOP_REG)
11413     {
11414       commitPair (AOP (result), getPairId (AOP (right)), ic, TRUE);
11415     }
11416   else if (getPairId (AOP (right)) == PAIR_IY)
11417     {
11418       while (size--)
11419         {
11420           if (size == 0)
11421             {
11422               if (IS_TLCS90)
11423                 {
11424                   emit2 ("push iy");
11425                   emit2 ("ld a, 0(sp)");
11426                   emit2 ("inc sp");
11427                   emit2 ("inc sp");
11428                   cost (5, 26);
11429                 }
11430               else
11431                 {
11432                   emit2 ("push iy");
11433                   emit2 ("dec sp");
11434                   emit2 ("pop af");
11435                   emit2 ("inc sp");
11436                   regalloc_dry_run_cost += 5;
11437                 }
11438               if (AOP_TYPE (result) == AOP_IY) /* Take care not to overwrite iy */
11439                 {
11440                   emit2 ("ld (%s+%d), a", AOP (result)->aopu.aop_dir, size);
11441                   regalloc_dry_run_cost += 3;
11442                 }
11443               else
11444                 cheapMove (AOP (result), size, ASMOP_A, 0, true);
11445             }
11446           else if (size == 1)
11447             {
11448               if (AOP_TYPE (result) == AOP_IY) /* Take care not to overwrite iy */
11449                 {
11450                   emit2 ("ld (%s), iy", AOP (result)->aopu.aop_dir);
11451                   regalloc_dry_run_cost += 4;
11452                   size--;
11453                 }
11454               else if (AOP_TYPE (result) == AOP_EXSTK || IS_TLCS90) /* Take care not to overwrite iy */
11455                 {
11456                   bool pushed_pair = FALSE;
11457                   PAIR_ID pair = getDeadPairId (ic);
11458                   if (pair == PAIR_INVALID)
11459                   {
11460                     pair = PAIR_HL;
11461                     _push(pair);
11462                     pushed_pair= TRUE;
11463                   }
11464                   fetchPair (pair, AOP (right));
11465                   commitPair (AOP (result), pair, ic, FALSE);
11466                   if (pushed_pair)
11467                     _pop (pair);
11468                   size--;
11469                 }
11470               else
11471                 {
11472                   emit2 ("push iy");
11473                   emit2 ("pop af");
11474                   regalloc_dry_run_cost += 3;
11475                   cheapMove (AOP (result), size, ASMOP_A, 0, true);
11476                 }
11477             }
11478           else
11479             {
11480               if (AOP_TYPE (result) == AOP_IY) /* Take care not to overwrite iy */
11481                 {
11482                   cheapMove (ASMOP_A, 0, ASMOP_ZERO, 0, true);
11483                   emit2 ("ld (%s+%d), a", AOP (result)->aopu.aop_dir, size);
11484                   regalloc_dry_run_cost += 3;
11485                 }
11486               else
11487                 cheapMove (AOP (result), size, ASMOP_ZERO, 0, true);
11488             }
11489         }
11490     }
11491   else if (size == 2 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && isPairDead (PAIR_DE, ic) && (IS_GB /*|| IY_RESERVED */ ))
11492     {
11493       /* Special case.  Load into a and d, then load out. */
11494       cheapMove (ASMOP_A, 0, AOP (right), 0, true);
11495       emit3_o (A_LD, ASMOP_E, 0, AOP (right), 1);
11496       cheapMove (AOP (result), 0, ASMOP_A, 0, true);
11497       cheapMove (AOP (result), 1, ASMOP_E, 0, true);
11498     }
11499   else if (size == 4 && requiresHL (AOP (right)) && requiresHL (AOP (result)) && isPairDead (PAIR_DE, ic) && (IS_GB /*|| IY_RESERVED */ ))
11500     {
11501       /* Special case - simple memcpy */
11502       if (!regalloc_dry_run)
11503         {
11504           aopGet (AOP (right), LSB, FALSE);
11505           emit2 ("ld d, h");
11506           emit2 ("ld e, l");
11507           aopGet (AOP (result), LSB, FALSE);
11508         }
11509       regalloc_dry_run_cost += 8;       // Todo: More exact cost here!
11510 
11511       while (size--)
11512         {
11513           emit2 ("ld a, (de)");
11514           /* Peephole will optimise this. */
11515           emit2 ("ld (hl), a");
11516           regalloc_dry_run_cost += 2;
11517           if (size != 0)
11518             {
11519               emit2 ("inc hl");
11520               emit2 ("inc de");
11521               regalloc_dry_run_cost += 2;
11522             }
11523         }
11524       spillPair (PAIR_HL);
11525     }
11526   else
11527     {
11528       if (!IS_GB &&             /* gbz80 doesn't have ldir */
11529           (AOP_TYPE (result) == AOP_STK || AOP_TYPE (result) == AOP_EXSTK || AOP_TYPE (result) == AOP_DIR
11530            || AOP_TYPE (result) == AOP_IY) && (AOP_TYPE (right) == AOP_STK || AOP_TYPE (right) == AOP_EXSTK
11531                || AOP_TYPE (right) == AOP_DIR || AOP_TYPE (right) == AOP_IY) && size >= 2)
11532         {
11533           /* This estimation is only accurate, if neither operand is AOP_EXSTK, and we are optimizing for code size or targeting the z80 or z180. */
11534           int sizecost_n, sizecost_l, cyclecost_n, cyclecost_l;
11535           const bool hl_alive = !isPairDead (PAIR_HL, ic);
11536           const bool de_alive = !isPairDead (PAIR_DE, ic);
11537           const bool bc_alive = !isPairDead (PAIR_BC, ic);
11538           bool l_better;
11539           sizecost_n = 6 * size;
11540           sizecost_l = 13 + hl_alive * 2 + de_alive * 2 + bc_alive * 2 - (AOP_TYPE (right) == AOP_DIR
11541                        || AOP_TYPE (right) == AOP_IY) - (AOP_TYPE (result) ==
11542                            AOP_DIR
11543                            || AOP_TYPE (result)
11544                            == AOP_IY) * 2;
11545           if (IS_Z180 || IS_EZ80_Z80)
11546             cyclecost_n = 30 * size;
11547           else                  /* Z80 */
11548             cyclecost_n = 38 * size;
11549           if (IS_Z180 || IS_EZ80_Z80)
11550             cyclecost_l = 14 * size + 42 + hl_alive * 22 + de_alive * 22 + bc_alive * 22 - (AOP_TYPE (right) == AOP_DIR
11551                           || AOP_TYPE (right) ==
11552                           AOP_IY) * 7 - (AOP_TYPE (result) ==
11553                                          AOP_DIR
11554                                          || AOP_TYPE (result)
11555                                          == AOP_IY) * 10;
11556           else                  /* Z80 */
11557             cyclecost_l = 21 * size + 51 + hl_alive * 20 + de_alive * 20 + bc_alive * 20 - (AOP_TYPE (right) == AOP_DIR
11558                           || AOP_TYPE (right) ==
11559                           AOP_IY) * 11 - (AOP_TYPE (result) ==
11560                                           AOP_DIR
11561                                           || AOP_TYPE (result)
11562                                           == AOP_IY) * 15;
11563 
11564           if (optimize.codeSize)
11565             l_better = (sizecost_l < sizecost_n || sizecost_l == sizecost_n && cyclecost_l < cyclecost_n);
11566           else
11567             l_better = (cyclecost_l < cyclecost_n || cyclecost_l == cyclecost_n && sizecost_l < sizecost_n);
11568           if (l_better)
11569             {
11570               if (hl_alive)
11571                 _push (PAIR_HL);
11572               if (de_alive)
11573                 _push (PAIR_DE);
11574               if (bc_alive)
11575                 _push (PAIR_BC);
11576 
11577               if (AOP_TYPE (result) == AOP_STK || AOP_TYPE (result) == AOP_EXSTK)
11578                 {
11579                   int fp_offset =
11580                     AOP (result)->aopu.aop_stk + offset + (AOP (result)->aopu.aop_stk >
11581                         0 ? _G.stack.param_offset : 0);
11582                   int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
11583                   emit2 ("ld hl, #%d", sp_offset);
11584                   emit2 ("add hl, sp");
11585                   emit2 ("ex de, hl");
11586                   regalloc_dry_run_cost += 5;
11587                 }
11588               else
11589                 {
11590                   emit2 ("ld de, #%s", AOP (IC_RESULT (ic))->aopu.aop_dir);
11591                   regalloc_dry_run_cost += 3;
11592                 }
11593 
11594               if (AOP_TYPE (right) == AOP_STK || AOP_TYPE (right) == AOP_EXSTK)
11595                 {
11596                   int fp_offset =
11597                     AOP (right)->aopu.aop_stk + offset + (AOP (right)->aopu.aop_stk >
11598                         0 ? _G.stack.param_offset : 0);
11599                   int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
11600                   emit2 ("ld hl, #%d", sp_offset);
11601                   emit2 ("add hl, sp");
11602                   regalloc_dry_run_cost += 4;
11603                 }
11604               else
11605                 {
11606                   emit2 ("ld hl, #%s", AOP (IC_RIGHT (ic))->aopu.aop_dir);
11607                   regalloc_dry_run_cost += 3;
11608                 }
11609               spillPair (PAIR_HL);
11610 
11611               if (size <= 2 + optimize.codeSpeed)
11612                 for(int i = 0; i < size; i++)
11613                   {
11614                     emit2 ("ldi");
11615                     regalloc_dry_run_cost += 2;
11616                   }
11617               else
11618                 {
11619                   emit2 ("ld bc, #%d", size);
11620                   emit2 ("ldir");
11621                   regalloc_dry_run_cost += 5;
11622                 }
11623 
11624               if (bc_alive)
11625                 _pop (PAIR_BC);
11626               if (de_alive)
11627                 _pop (PAIR_DE);
11628               if (hl_alive)
11629                 _pop (PAIR_HL);
11630 
11631               goto release;
11632             }
11633         }
11634       if ((result->aop->type == AOP_REG || result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK) && (right->aop->type == AOP_REG || right->aop->type == AOP_STK || right->aop->type == AOP_LIT))
11635         genMove (result->aop, right->aop, !bitVectBitValue (ic->rSurv, A_IDX), isPairDead (PAIR_HL, ic));
11636       else
11637         while (size--)
11638           {
11639             /* PENDING: do this check better */
11640             if ((IS_GB || IY_RESERVED) && requiresHL (AOP (right)) && requiresHL (AOP (result)))
11641               {
11642                 _push (PAIR_HL);
11643                 cheapMove (ASMOP_A, 0, AOP (right), offset, true);
11644                 cheapMove (AOP (result), offset, ASMOP_A, 0, true);
11645                 _pop (PAIR_HL);
11646                 spillPair (PAIR_HL);
11647               }
11648             else
11649               cheapMove (AOP (result), offset, AOP (right), offset, true);
11650             offset++;
11651           }
11652     }
11653 
11654 release:
11655   freeAsmop (right, NULL);
11656   freeAsmop (result, NULL);
11657 }
11658 
11659 /*-----------------------------------------------------------------*/
11660 /* genJumpTab - generate code for jump table                       */
11661 /*-----------------------------------------------------------------*/
11662 static void
genJumpTab(const iCode * ic)11663 genJumpTab (const iCode *ic)
11664 {
11665   symbol *jtab = NULL;
11666   operand *jtcond = IC_JTCOND (ic);
11667   bool pushed_pair = FALSE;
11668   PAIR_ID pair;
11669 
11670   aopOp (jtcond, ic, FALSE, FALSE);
11671 
11672   // Choose extra pair DE or BC for addition
11673   if (AOP_TYPE (jtcond) == AOP_REG && AOP (jtcond)->aopu.aop_reg[0]->rIdx == E_IDX && isPairDead (PAIR_DE, ic))
11674     pair = PAIR_DE;
11675   else if (AOP_TYPE (jtcond) == AOP_REG && AOP (jtcond)->aopu.aop_reg[0]->rIdx == C_IDX && isPairDead (PAIR_BC, ic))
11676     pair = PAIR_BC;
11677   else if ((pair = getDeadPairId (ic)) == PAIR_INVALID)
11678     pair = PAIR_DE;
11679 
11680   if (!isPairDead (pair, ic))
11681     {
11682       _push (pair);
11683       pushed_pair = TRUE;
11684     }
11685 
11686   cheapMove (pair == PAIR_DE ? ASMOP_E : ASMOP_C, 0, AOP (jtcond), 0, true);
11687   if (!regalloc_dry_run)
11688     {
11689       emit2 ("ld %s, !zero", _pairs[pair].h);
11690       jtab = newiTempLabel (NULL);
11691     }
11692   regalloc_dry_run_cost += 2;
11693   spillPair (PAIR_HL);
11694   if (!regalloc_dry_run)
11695     {
11696       emit2 ("ld hl, !immed!tlabel", labelKey2num (jtab->key));
11697       emit2 ("add hl, %s", _pairs[pair].name);
11698       emit2 ("add hl, %s", _pairs[pair].name);
11699       emit2 ("add hl, %s", _pairs[pair].name);
11700     }
11701   regalloc_dry_run_cost += 5;
11702   freeAsmop (IC_JTCOND (ic), NULL);
11703 
11704   if (pushed_pair)
11705     _pop (pair);
11706 
11707   if (!regalloc_dry_run)
11708     {
11709       emit2 ("jp !*hl");
11710       emitLabelSpill (jtab);
11711     }
11712   regalloc_dry_run_cost += 1;
11713   /* now generate the jump labels */
11714   for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
11715     if (!regalloc_dry_run)
11716       emit2 ("jp !tlabel", labelKey2num (jtab->key));
11717   /*regalloc_dry_run_cost += 3 doesn't matter and might overflow cost */
11718 }
11719 
11720 /*-----------------------------------------------------------------*/
11721 /* genCast - gen code for casting                                  */
11722 /*-----------------------------------------------------------------*/
11723 static void
genCast(const iCode * ic)11724 genCast (const iCode *ic)
11725 {
11726   operand *result = IC_RESULT (ic);
11727   sym_link *rtype = operandType (IC_RIGHT (ic));
11728   operand *right = IC_RIGHT (ic);
11729   int size, offset;
11730   bool surviving_a = !options.oldralloc && bitVectBitValue (ic->rSurv, A_IDX);
11731   bool pushed_a = FALSE;
11732 
11733   /* if they are equivalent then do nothing */
11734   if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
11735     return;
11736 
11737   aopOp (right, ic, FALSE, FALSE);
11738   aopOp (result, ic, FALSE, FALSE);
11739 
11740   /* if the result is a bit */
11741   if (AOP_TYPE (result) == AOP_CRY)
11742     {
11743       wassertl (0, "Tried to cast to a bit");
11744     }
11745 
11746   /* casting to bool */
11747   if (IS_BOOL (operandType (result)) && IS_RAB && right->aop->size == 2 &&
11748     (aopInReg (right->aop, 0, HL_IDX) && isPairDead (PAIR_HL, ic)|| aopInReg (right->aop, 0, IY_IDX) && isPairDead (PAIR_IY, ic)))
11749     {
11750       bool iy = aopInReg (right->aop, 0, IY_IDX);
11751       emit2 ("bool %s", _pairs[getPairId (right->aop)].name);
11752       cheapMove (result->aop, 0, iy ? ASMOP_IYL : ASMOP_L, 0, !bitVectBitValue (ic->rSurv, A_IDX));
11753       goto release;
11754     }
11755   if (IS_BOOL (operandType (result)))
11756     {
11757       _castBoolean (right);
11758       outAcc (result);
11759       goto release;
11760     }
11761 
11762   /* if they are the same size or less */
11763   if (AOP_SIZE (result) <= AOP_SIZE (right))
11764     {
11765       genAssign (ic);
11766       goto release;
11767     }
11768 
11769   /* So we now know that the size of destination is greater
11770      than the size of the source */
11771   genMove_o (result->aop, 0, right->aop, 0, right->aop->size - 1, true, isPairDead (PAIR_HL, ic));
11772 
11773   /* now depending on the sign of the destination */
11774   size = result->aop->size - right->aop->size;
11775   offset = right->aop->size - 1;
11776   /* Unsigned or not an integral type - fill with zeros */
11777   if (IS_BOOL (rtype) || !IS_SPEC (rtype) || SPEC_USIGN (rtype) || AOP_TYPE (right) == AOP_CRY)
11778     {
11779       cheapMove (result->aop, offset, right->aop, offset, true);
11780       offset++;
11781       genMove_o (result->aop, offset, ASMOP_ZERO, 0, size, true, false);
11782     }
11783   else
11784     {
11785       if (surviving_a && !pushed_a)
11786         _push (PAIR_AF), pushed_a = TRUE;
11787 
11788       cheapMove (ASMOP_A, 0, AOP (right), offset, true);
11789       if (AOP (right)->type != AOP_REG || AOP (result)->type != AOP_REG || AOP (right)->aopu.aop_reg[offset] != AOP (result)->aopu.aop_reg[offset])
11790         cheapMove (AOP (result), offset, ASMOP_A, 0, true);
11791       offset++;
11792 
11793       /* we need to extend the sign */
11794       emit3 (A_RLA, 0, 0);
11795       emit3 (A_SBC, ASMOP_A, ASMOP_A);
11796       while (size--)
11797         cheapMove (AOP (result), offset++, ASMOP_A, 0, true);
11798     }
11799 
11800 release:
11801   if (pushed_a)
11802     _pop (PAIR_AF);
11803   freeAsmop (right, NULL);
11804   freeAsmop (result, NULL);
11805 }
11806 
11807 /*-----------------------------------------------------------------*/
11808 /* genReceive - generate code for a receive iCode                  */
11809 /*-----------------------------------------------------------------*/
11810 static void
genReceive(const iCode * ic)11811 genReceive (const iCode *ic)
11812 {
11813   operand *result = IC_RESULT (ic);
11814   aopOp (result, ic, FALSE, FALSE);
11815 
11816   genMove (result->aop, ASMOP_RETURN, true, isPairDead (PAIR_HL, ic));
11817 
11818   freeAsmop (IC_RESULT (ic), NULL);
11819 }
11820 
11821 /*-----------------------------------------------------------------*/
11822 /* genDummyRead - generate code for dummy read of volatiles        */
11823 /*-----------------------------------------------------------------*/
11824 static void
genDummyRead(const iCode * ic)11825 genDummyRead (const iCode * ic)
11826 {
11827   operand *op;
11828   int size, offset;
11829 
11830   op = IC_RIGHT (ic);
11831   if (op && IS_SYMOP (op))
11832     {
11833       aopOp (op, ic, FALSE, FALSE);
11834 
11835       /* general case */
11836       size = AOP_SIZE (op);
11837       offset = 0;
11838 
11839       while (size--)
11840         {
11841           _moveA3 (AOP (op), offset);
11842           offset++;
11843         }
11844 
11845       freeAsmop (op, NULL);
11846     }
11847 
11848   op = IC_LEFT (ic);
11849   if (op && IS_SYMOP (op))
11850     {
11851       aopOp (op, ic, FALSE, FALSE);
11852 
11853       /* general case */
11854       size = AOP_SIZE (op);
11855       offset = 0;
11856 
11857       while (size--)
11858         {
11859           _moveA3 (AOP (op), offset);
11860           offset++;
11861         }
11862 
11863       freeAsmop (op, NULL);
11864     }
11865 }
11866 
11867 /*-----------------------------------------------------------------*/
11868 /* genCritical - generate code for start of a critical sequence    */
11869 /*-----------------------------------------------------------------*/
11870 static void
genCritical(const iCode * ic)11871 genCritical (const iCode * ic)
11872 {
11873   symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
11874 
11875   if (IS_GB || IS_RAB || IS_TLCS90)
11876     {
11877       emit2 ("!di");
11878       regalloc_dry_run_cost += 1;
11879     }
11880   else if (IC_RESULT (ic))
11881     {
11882       aopOp (IC_RESULT (ic), ic, true, false);
11883       cheapMove (IC_RESULT (ic)->aop, 0, ASMOP_ZERO, 0, true);
11884       if (!regalloc_dry_run)
11885         {
11886           //get interrupt enable flag IFF2 into P/O
11887           emit2 ("ld a,i");
11888 
11889           //disable interrupt
11890           emit2 ("!di");
11891           //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
11892           emit2 ("jp PO, !tlabel", labelKey2num (tlbl->key));
11893         }
11894       regalloc_dry_run_cost += 5;
11895       cheapMove (IC_RESULT (ic)->aop, 0, ASMOP_ONE, 0, true);
11896       if (!regalloc_dry_run)
11897         {
11898           emit2 ("!tlabeldef", labelKey2num ((tlbl->key)));
11899           genLine.lineCurr->isLabel = 1;
11900         }
11901       freeAsmop (IC_RESULT (ic), NULL);
11902     }
11903   else
11904     {
11905       //get interrupt enable flag IFF2 into P/O
11906       emit2 ("ld a,i");
11907 
11908       //disable interrupt
11909       emit2 ("!di");
11910       regalloc_dry_run_cost += 2;
11911       //save P/O flag
11912       if (!regalloc_dry_run)    // _push unbalances _G.stack.pushed.
11913         _push (PAIR_AF);
11914       else
11915         regalloc_dry_run_cost++;
11916     }
11917 }
11918 
11919 /*-----------------------------------------------------------------*/
11920 /* genEndCritical - generate code for end of a critical sequence   */
11921 /*-----------------------------------------------------------------*/
11922 static void
genEndCritical(const iCode * ic)11923 genEndCritical (const iCode * ic)
11924 {
11925   symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
11926 
11927   if (IS_GB || IS_TLCS90)
11928     {
11929       emit2 ("!ei");
11930       regalloc_dry_run_cost += 1;
11931     }
11932   else if (IS_RAB)
11933     {
11934       emit2 ("ipres");
11935       regalloc_dry_run_cost += 1;
11936     }
11937   else if (IC_RIGHT (ic))
11938     {
11939       aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
11940       _toBoolean (IC_RIGHT (ic), TRUE);
11941 
11942       if (!regalloc_dry_run)
11943         {
11944           //don't enable interrupts if they were off before
11945           emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
11946           emit2 ("!ei");
11947           emitLabelSpill (tlbl);
11948         }
11949       regalloc_dry_run_cost += 4;
11950       freeAsmop (IC_RIGHT (ic), NULL);
11951     }
11952   else
11953     {
11954       //restore P/O flag
11955       if (!regalloc_dry_run)    // _pop unbalances _G.stack.pushed.
11956         _pop (PAIR_AF);
11957       else
11958         regalloc_dry_run_cost++;
11959       //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
11960       //don't enable interrupts as they were off before
11961       if (!regalloc_dry_run)
11962         {
11963           emit2 ("jp PO, !tlabel", labelKey2num (tlbl->key));
11964           emit2 ("!ei");
11965           emit2 ("!tlabeldef", labelKey2num ((tlbl->key)));
11966           genLine.lineCurr->isLabel = 1;
11967         }
11968       regalloc_dry_run_cost += 4;
11969     }
11970 }
11971 
11972 #if 0                           //Disabled since it doesn't work for arrays of float.
11973 enum
11974 {
11975   /** Maximum number of bytes to emit per line. */
11976   DBEMIT_MAX_RUN = 8
11977 };
11978 
11979 /** Context for the byte output chunker. */
11980 typedef struct
11981 {
11982   unsigned char buffer[DBEMIT_MAX_RUN];
11983   int pos;
11984 } DBEMITCTX;
11985 
11986 
11987 /** Flushes a byte chunker by writing out all in the buffer and
11988     reseting.
11989 */
11990 static void
11991 _dbFlush (DBEMITCTX * self)
11992 {
11993   char line[256];
11994 
11995   if (self->pos > 0)
11996     {
11997       int i;
11998       sprintf (line, ".db 0x%02X", self->buffer[0]);
11999 
12000       for (i = 1; i < self->pos; i++)
12001         {
12002           sprintf (line + strlen (line), ", 0x%02X", self->buffer[i]);
12003         }
12004       emit2 (line);
12005     }
12006   self->pos = 0;
12007 }
12008 
12009 /** Write out another byte, buffering until a decent line is
12010     generated.
12011 */
12012 static void
12013 _dbEmit (DBEMITCTX * self, int c)
12014 {
12015   if (self->pos == DBEMIT_MAX_RUN)
12016     {
12017       _dbFlush (self);
12018     }
12019   self->buffer[self->pos++] = c;
12020 }
12021 
12022 /** Context for a simple run length encoder. */
12023 typedef struct
12024 {
12025   unsigned last;
12026   unsigned char buffer[128];
12027   int pos;
12028   /** runLen may be equivalent to pos. */
12029   int runLen;
12030 } RLECTX;
12031 
12032 enum
12033 {
12034   RLE_CHANGE_COST = 4,
12035   RLE_MAX_BLOCK = 127
12036 };
12037 
12038 /** Flush the buffer of a run length encoder by writing out the run or
12039     data that it currently contains.
12040 */
12041 static void
12042 _rleCommit (RLECTX * self)
12043 {
12044   int i;
12045   if (self->pos != 0)
12046     {
12047       DBEMITCTX db;
12048       memset (&db, 0, sizeof (db));
12049 
12050       emit2 (".db %u", self->pos);
12051 
12052       for (i = 0; i < self->pos; i++)
12053         {
12054           _dbEmit (&db, self->buffer[i]);
12055         }
12056       _dbFlush (&db);
12057     }
12058   /* Reset */
12059   self->pos = 0;
12060 }
12061 
12062 /* Encoder design:
12063    Can get either a run or a block of random stuff.
12064    Only want to change state if a good run comes in or a run ends.
12065    Detecting run end is easy.
12066    Initial state?
12067 
12068    Say initial state is in run, len zero, last zero.  Then if you get a
12069    few zeros then something else then a short run will be output.
12070    Seems OK.  While in run mode, keep counting.  While in random mode,
12071    keep a count of the run.  If run hits margin, output all up to run,
12072    restart, enter run mode.
12073 */
12074 
12075 /** Add another byte into the run length encoder, flushing as
12076     required.  The run length encoder uses the Amiga IFF style, where
12077     a block is prefixed by its run length.  A positive length means
12078     the next n bytes pass straight through.  A negative length means
12079     that the next byte is repeated -n times.  A zero terminates the
12080     chunks.
12081 */
12082 static void
12083 _rleAppend (RLECTX * self, unsigned c)
12084 {
12085   int i;
12086 
12087   if (c != self->last)
12088     {
12089       /* The run has stopped.  See if it is worthwhile writing it out
12090          as a run.  Note that the random data comes in as runs of
12091          length one.
12092        */
12093       if (self->runLen > RLE_CHANGE_COST)
12094         {
12095           /* Yes, worthwhile. */
12096           /* Commit whatever was in the buffer. */
12097           _rleCommit (self);
12098           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
12099         }
12100       else
12101         {
12102           /* Not worthwhile.  Append to the end of the random list. */
12103           for (i = 0; i < self->runLen; i++)
12104             {
12105               if (self->pos >= RLE_MAX_BLOCK)
12106                 {
12107                   /* Commit. */
12108                   _rleCommit (self);
12109                 }
12110               self->buffer[self->pos++] = self->last;
12111             }
12112         }
12113       self->runLen = 1;
12114       self->last = c;
12115     }
12116   else
12117     {
12118       if (self->runLen >= RLE_MAX_BLOCK)
12119         {
12120           /* Commit whatever was in the buffer. */
12121           _rleCommit (self);
12122 
12123           emit2 ("!db !immed-%u,!immedbyte", self->runLen, self->last);
12124           self->runLen = 0;
12125         }
12126       self->runLen++;
12127     }
12128 }
12129 
12130 static void
12131 _rleFlush (RLECTX * self)
12132 {
12133   _rleAppend (self, -1);
12134   _rleCommit (self);
12135   self->pos = 0;
12136   self->last = 0;
12137   self->runLen = 0;
12138 }
12139 
12140 /** genArrayInit - Special code for initialising an array with constant
12141    data.
12142 */
12143 
12144 static void
12145 genArrayInit (iCode * ic)
12146 {
12147   literalList *iLoop;
12148   int ix;
12149   int elementSize = 0, eIndex, i;
12150   unsigned val, lastVal;
12151   sym_link *type;
12152   RLECTX rle;
12153 
12154   memset (&rle, 0, sizeof (rle));
12155 
12156   aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
12157 
12158   _saveRegsForCall (ic, 0);
12159 
12160   fetchPair (PAIR_HL, AOP (IC_LEFT (ic)));
12161   emit2 ("call __initrleblock");
12162 
12163   type = operandType (IC_LEFT (ic));
12164 
12165   if (type && type->next)
12166     {
12167       if (IS_SPEC (type->next) || IS_PTR (type->next))
12168         {
12169           elementSize = getSize (type->next);
12170         }
12171       else if (IS_ARRAY (type->next) && type->next->next)
12172         {
12173           elementSize = getSize (type->next->next);
12174         }
12175       else
12176         {
12177           printTypeChainRaw (type, NULL);
12178           wassertl (0, "Can't determine element size in genArrayInit.");
12179         }
12180     }
12181   else
12182     {
12183       wassertl (0, "Can't determine element size in genArrayInit.");
12184     }
12185 
12186   wassertl ((elementSize > 0) && (elementSize <= 4), "Illegal element size in genArrayInit.");
12187 
12188   iLoop = IC_ARRAYILIST (ic);
12189   lastVal = (unsigned) - 1;
12190 
12191   /* Feed all the bytes into the run length encoder which will handle
12192      the actual output.
12193      This works well for mixed char data, and for random int and long
12194      data.
12195    */
12196   while (iLoop)
12197     {
12198       ix = iLoop->count;
12199 
12200       for (i = 0; i < ix; i++)
12201         {
12202           for (eIndex = 0; eIndex < elementSize; eIndex++)
12203             {
12204               val = (((int) iLoop->literalValue) >> (eIndex * 8)) & 0xff;
12205               _rleAppend (&rle, val);
12206             }
12207         }
12208 
12209       iLoop = iLoop->next;
12210     }
12211 
12212   _rleFlush (&rle);
12213   /* Mark the end of the run. */
12214   emit2 (".db 0");
12215 
12216   _restoreRegsAfterCall ();
12217 
12218   spillCached ();
12219 
12220   freeAsmop (IC_LEFT (ic), NULL, ic);
12221 }
12222 #endif
12223 
12224 static void
setupForMemcpy(const iCode * ic,const operand * to,const operand * from)12225 setupForMemcpy (const iCode *ic, const operand *to, const operand *from)
12226 {
12227   /* Both are in regs. Let regMove() do the shuffling. */
12228   if (AOP_TYPE (to) == AOP_REG && AOP_TYPE (from) == AOP_REG)
12229     {
12230       const short larray[4] = {E_IDX, D_IDX, L_IDX, H_IDX};
12231       short oparray[4];
12232       oparray[0] = AOP (to)->aopu.aop_reg[0]->rIdx;
12233       oparray[1] = AOP (to)->aopu.aop_reg[1]->rIdx;
12234       oparray[2] = AOP (from)->aopu.aop_reg[0]->rIdx;
12235       oparray[3] = AOP (from)->aopu.aop_reg[1]->rIdx;
12236 
12237       regMove (larray, oparray, 4, FALSE);
12238     }
12239   else
12240     {
12241       /* DE is free. Write it first. */
12242       if (AOP_TYPE (from) != AOP_REG || AOP (from)->aopu.aop_reg[0]->rIdx != E_IDX && AOP (from)->aopu.aop_reg[0]->rIdx != D_IDX && AOP (from)->aopu.aop_reg[1]->rIdx != E_IDX && AOP (from)->aopu.aop_reg[1]->rIdx != D_IDX)
12243         {
12244           fetchPair (PAIR_DE, AOP (to));
12245           fetchPair (PAIR_HL, AOP (from));
12246         }
12247       /* HL is free. Write it first. */
12248       else if (AOP_TYPE (to) != AOP_REG || AOP (to)->aopu.aop_reg[0]->rIdx != L_IDX && AOP (to)->aopu.aop_reg[0]->rIdx != H_IDX && AOP (to)->aopu.aop_reg[1]->rIdx != L_IDX && AOP (to)->aopu.aop_reg[1]->rIdx != H_IDX)
12249         {
12250           fetchPair (PAIR_HL, AOP (from));
12251           fetchPair (PAIR_DE, AOP (to));
12252         }
12253       /* L is free, but H is not. */
12254       else if ((AOP_TYPE (to) != AOP_REG || AOP (to)->aopu.aop_reg[0]->rIdx != L_IDX && AOP (to)->aopu.aop_reg[1]->rIdx != L_IDX) &&
12255         (AOP_TYPE (from) != AOP_REG || AOP (from)->aopu.aop_reg[0]->rIdx != L_IDX && AOP (from)->aopu.aop_reg[1]->rIdx != L_IDX))
12256         {
12257           cheapMove (ASMOP_L, 0, AOP (from), 0, true);
12258           fetchPair (PAIR_DE, AOP (to));
12259           cheapMove (ASMOP_H, 0, AOP (from), 1, true);
12260         }
12261       /* H is free, but L is not. */
12262       else
12263         {
12264           cheapMove (ASMOP_H, 0, AOP (from), 1, true);
12265           fetchPair (PAIR_DE, AOP (to));
12266           cheapMove (ASMOP_L, 0, AOP (from), 0, true);
12267         }
12268     }
12269 }
12270 
12271 static void
genBuiltInMemcpy(const iCode * ic,int nparams,operand ** pparams)12272 genBuiltInMemcpy (const iCode *ic, int nparams, operand **pparams)
12273 {
12274   int i;
12275   operand *from, *to, *count;
12276   bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
12277   unsigned int n;
12278 
12279   for (i = 0; i < nparams; i++)
12280     aopOp (pparams[i], ic, FALSE, FALSE);
12281 
12282   wassertl (!IS_GB, "Built-in memcpy() not available on gbz80.");
12283   wassertl (nparams == 3, "Built-in memcpy() must have three parameters.");
12284   /* Check for zero length copy. */
12285   wassertl (AOP_TYPE (pparams[2]) == AOP_LIT, "Last parameter to builtin memcpy() must be literal.");
12286 
12287   count = pparams[2];
12288   from = pparams[1];
12289   to = pparams[0];
12290 
12291   if (!(n = (unsigned int) ulFromVal (AOP (pparams[2])->aopu.aop_lit)))
12292     goto done;
12293 
12294   if (!isPairDead (PAIR_HL, ic))
12295     {
12296       _push (PAIR_HL);
12297       saved_HL = TRUE;
12298     }
12299   if (!isPairDead (PAIR_DE, ic))
12300     {
12301       _push (PAIR_DE);
12302       saved_DE = TRUE;
12303     }
12304   if (!isPairDead (PAIR_BC, ic) && n > 2)
12305     {
12306       _push (PAIR_BC);
12307       saved_BC = TRUE;
12308     }
12309 
12310  setupForMemcpy (ic, to, from);
12311 
12312   if (n == 1)
12313     {
12314       emit2 ("ld a, (hl)");
12315       emit2 ("ld (de), a");
12316       regalloc_dry_run_cost += 2;
12317     }
12318   else if (n == 2)
12319     {
12320       emit2 ("ldi");
12321       emit2 ("ld a, (hl)");
12322       emit2 ("ld (de), a");
12323       regalloc_dry_run_cost += 4;
12324       if (!isPairDead (PAIR_BC, ic)) /* Restore bc. */
12325         {
12326           emit2 ("inc bc");
12327           regalloc_dry_run_cost++;
12328         }
12329     }
12330   else
12331     {
12332       fetchPair (PAIR_BC, AOP (count));
12333       emit2 ("ldir");
12334       regalloc_dry_run_cost += 2;
12335     }
12336 
12337   spillPair (PAIR_HL);
12338 
12339   if (saved_BC)
12340     _pop (PAIR_BC);
12341   if (saved_DE)
12342     _pop (PAIR_DE);
12343   if (saved_HL)
12344     _pop (PAIR_HL);
12345 
12346 done:
12347   freeAsmop (count, NULL);
12348   freeAsmop (to, NULL);
12349   freeAsmop (from, NULL);
12350 
12351   /* No need to assign result - would have used ordinary memcpy() call instead. */
12352 }
12353 
12354 static void
setupForMemset(const iCode * ic,const operand * dst,const operand * c,bool direct_c)12355 setupForMemset (const iCode *ic, const operand *dst, const operand *c, bool direct_c)
12356 {
12357   /* Both are in regs. Let regMove() do the shuffling. */
12358   if (AOP_TYPE (dst) == AOP_REG && !direct_c && AOP_TYPE (c) == AOP_REG)
12359     {
12360       const short larray[2] = {L_IDX, H_IDX};
12361       short oparray[2];
12362       bool early_a = AOP_TYPE (c) == AOP_REG && (AOP (c)->aopu.aop_reg[0]->rIdx == L_IDX || AOP (c)->aopu.aop_reg[0]->rIdx == H_IDX);
12363 
12364       if (early_a)
12365         cheapMove (ASMOP_A, 0, AOP (c), 0, true);
12366 
12367       oparray[0] = AOP (dst)->aopu.aop_reg[0]->rIdx;
12368       oparray[1] = AOP (dst)->aopu.aop_reg[1]->rIdx;
12369 
12370       regMove (larray, oparray, 2, early_a);
12371 
12372       if (!early_a)
12373         cheapMove (ASMOP_A, 0, AOP (c), 0, true);
12374     }
12375   else if (AOP_TYPE (c) == AOP_REG && requiresHL (AOP (c)))
12376     {
12377       cheapMove (ASMOP_A, 0, AOP (c), 0, true);
12378       if (AOP_TYPE (dst) == AOP_EXSTK)
12379         _push (PAIR_AF);
12380       fetchPair (PAIR_HL, AOP (dst));
12381       if (AOP_TYPE (dst) == AOP_EXSTK)
12382         _pop (PAIR_AF);
12383     }
12384   else
12385     {
12386       fetchPair (PAIR_HL, AOP (dst));
12387       if (!direct_c)
12388         {
12389           if (requiresHL (AOP (c)))
12390             _push (PAIR_HL);
12391           cheapMove (ASMOP_A, 0, AOP (c), 0, true);
12392           if (requiresHL (AOP (c)))
12393             _pop (PAIR_HL);
12394         }
12395     }
12396 }
12397 
12398 static void
genBuiltInMemset(const iCode * ic,int nParams,operand ** pparams)12399 genBuiltInMemset (const iCode *ic, int nParams, operand **pparams)
12400 {
12401   operand *dst, *c, *n;
12402   bool direct_c, direct_cl;
12403   bool indirect_c;
12404   bool preinc = FALSE;
12405   unsigned long sizecost_ldir, sizecost_direct, sizecost_loop;
12406   bool double_loop;
12407   unsigned size;
12408   bool live_BC = !isPairDead (PAIR_BC, ic), live_DE = !isPairDead (PAIR_DE, ic), live_HL = !isPairDead (PAIR_HL, ic), live_B = bitVectBitValue (ic->rSurv, B_IDX);
12409   bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
12410 
12411   wassertl (nParams == 3, "Built-in memset() must have three parameters");
12412 
12413   dst = pparams[0];
12414   c = pparams[1];
12415   n = pparams[2];
12416 
12417   aopOp (c, ic, FALSE, FALSE);
12418   aopOp (dst, ic, FALSE, FALSE);
12419   aopOp (n, ic, FALSE, FALSE);
12420 
12421   wassertl (AOP_TYPE (n) == AOP_LIT, "Last parameter to builtin memset() must be literal.");
12422   if(!(size = ulFromVal (AOP (n)->aopu.aop_lit)))
12423     goto done;
12424 
12425   direct_c = (AOP_TYPE (c) == AOP_LIT || AOP_TYPE (c) == AOP_REG && AOP (c)->aopu.aop_reg[0]->rIdx != H_IDX
12426               && AOP (c)->aopu.aop_reg[0]->rIdx != L_IDX);
12427   direct_cl = (AOP_TYPE (c) == AOP_LIT || AOP_TYPE (c) == AOP_REG && AOP (c)->aopu.aop_reg[0]->rIdx != H_IDX
12428               && AOP (c)->aopu.aop_reg[0]->rIdx != L_IDX && AOP (c)->aopu.aop_reg[0]->rIdx != B_IDX);
12429   indirect_c = IS_R3KA && ulFromVal (AOP (n)->aopu.aop_lit) > 1 && AOP_TYPE (c) == AOP_IY;
12430 
12431   double_loop = (size > 255 || optimize.codeSpeed);
12432 
12433   sizecost_direct = 3 + 2 * size - 1 + !direct_c * ld_cost (ASMOP_A, AOP (c));
12434   sizecost_direct += (live_HL) * 2;
12435   sizecost_loop = 9 + double_loop * 2 + ((size % 2) && double_loop) * 2 + !direct_cl * ld_cost (ASMOP_A, AOP (c));
12436   sizecost_loop += (live_HL + live_B) * 2;
12437   sizecost_ldir = indirect_c ? 11 : (12 + !direct_c * ld_cost (ASMOP_A, AOP (c)) - (IS_R3KA && !optimize.codeSpeed));
12438   sizecost_ldir += (live_HL + live_DE + live_BC) * 2;
12439 
12440   if (sizecost_direct <= sizecost_loop && sizecost_direct < sizecost_ldir) // straight-line code.
12441     {
12442       if (live_HL)
12443         {
12444           _push (PAIR_HL);
12445           saved_HL = TRUE;
12446         }
12447 
12448       setupForMemset (ic, dst, c, direct_c);
12449 
12450       regalloc_dry_run_cost += (size * 2 - 1);
12451       if (!regalloc_dry_run)
12452         while (size--)
12453 		  {
12454             emit2 ("ld (hl), %s", aopGet (direct_c ? AOP (c) : ASMOP_A, 0, FALSE));
12455             if (size)
12456               emit2 ("inc hl");
12457           }
12458     }
12459   else if (size <= 510 && sizecost_loop < sizecost_ldir) // Loop
12460     {
12461       symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel (NULL);
12462       symbol *tlbl2 = regalloc_dry_run ? 0 : newiTempLabel (NULL);
12463 
12464       if (live_HL)
12465         {
12466           _push (PAIR_HL);
12467           saved_HL = TRUE;
12468         }
12469       if (bitVectBitValue (ic->rSurv, B_IDX))
12470         {
12471           _push (PAIR_BC);
12472           saved_BC = TRUE;
12473         }
12474 
12475       setupForMemset (ic, dst, c, direct_cl);
12476 
12477       emit2 ("ld b, !immedbyte", double_loop ? (size / 2 + size % 2) : size);
12478       regalloc_dry_run_cost += 2;
12479 
12480       if (double_loop && size % 2)
12481         {
12482           if (!regalloc_dry_run)
12483             emit2 ("jr !tlabel", labelKey2num (tlbl2->key));
12484           regalloc_dry_run_cost += 2;
12485         }
12486 
12487       if (!regalloc_dry_run)
12488         {
12489           emitLabel (tlbl1);
12490           emit2 ("ld (hl), %s", aopGet (direct_cl ? AOP (c) : ASMOP_A, 0, FALSE));
12491           emit2 ("inc hl");
12492           if (double_loop)
12493             {
12494               if (size % 2)
12495                 emitLabel (tlbl2);
12496               emit2 ("ld (hl), %s", aopGet (direct_cl ? AOP (c) : ASMOP_A, 0, FALSE));
12497               emit2 ("inc hl");
12498             }
12499           emit2 ("djnz !tlabel", labelKey2num (tlbl1->key));
12500         }
12501       regalloc_dry_run_cost += (double_loop ? 6 : 4);
12502     }
12503   else // Use ldir / lsidr
12504     {
12505       if (live_HL)
12506         {
12507           _push (PAIR_HL);
12508           saved_HL = TRUE;
12509         }
12510       if (live_DE)
12511         {
12512           _push (PAIR_DE);
12513           saved_DE = TRUE;
12514         }
12515       if (live_BC)
12516         {
12517           _push (PAIR_BC);
12518           saved_BC = TRUE;
12519         }
12520 	  if (indirect_c)
12521 		{
12522 		  fetchPair (PAIR_DE, AOP (dst));
12523 		  emit2 ("ld hl, #%s", AOP (c)->aopu.aop_dir);
12524 		  regalloc_dry_run_cost += 3;
12525 		}
12526 	  else
12527 		{
12528 		  setupForMemset (ic, dst, c, direct_c);
12529 
12530 		  if (!regalloc_dry_run)
12531 		    emit2 ("ld (hl), %s", aopGet (direct_c ? AOP (c) : ASMOP_A, 0, FALSE));
12532 		  regalloc_dry_run_cost += (direct_c && AOP_TYPE (c) == AOP_LIT) ? 2 : 1;
12533 		  if (ulFromVal (AOP (n)->aopu.aop_lit) <= 1)
12534 		    goto done;
12535 
12536 		  emit2 ("ld e, l");
12537 		  emit2 ("ld d, h");
12538 		  regalloc_dry_run_cost += 2;
12539 		  if (!IS_R3KA || optimize.codeSpeed)
12540 		    {
12541 		      emit2 ("inc de");
12542 		      regalloc_dry_run_cost++;
12543 		      preinc = TRUE;
12544 		    }
12545 		}
12546 	  emit2 ("ld bc, !immedword", size - preinc);
12547 	  emit2 (IS_R3KA ? "lsidr" : "ldir");
12548 	  regalloc_dry_run_cost += 5;
12549     }
12550 
12551 done:
12552   spillPair (PAIR_HL);
12553 
12554   freeAsmop (n, NULL);
12555   freeAsmop (c, NULL);
12556   freeAsmop (dst, NULL);
12557 
12558 
12559   if (saved_BC)
12560     _pop (PAIR_BC);
12561   if (saved_DE)
12562     _pop (PAIR_DE);
12563   if (saved_HL)
12564     _pop (PAIR_HL);
12565 
12566   /* No need to assign result - would have used ordinary memset() call instead. */
12567 }
12568 
12569 static void
genBuiltInStrcpy(const iCode * ic,int nParams,operand ** pparams)12570 genBuiltInStrcpy (const iCode *ic, int nParams, operand **pparams)
12571 {
12572   operand *dst, *src;
12573   bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
12574   int i;
12575   bool SomethingReturned;
12576 
12577   SomethingReturned = (IS_ITEMP (IC_RESULT (ic)) &&
12578                       (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
12579                       OP_SYMBOL (IC_RESULT (ic))->spildir ||
12580                       OP_SYMBOL (IC_RESULT (ic))->accuse == ACCUSE_A)) || IS_TRUE_SYMOP (IC_RESULT (ic));
12581 
12582   wassertl (nParams == 2, "Built-in strcpy() must have two parameters.");
12583   wassertl (!IS_GB, "Built-in strcpy() not available for gbz80.");
12584 
12585   dst = pparams[0];
12586   src = pparams[1];
12587 
12588   for (i = 0; i < nParams; i++)
12589     aopOp (pparams[i], ic, FALSE, FALSE);
12590 
12591   if (!isPairDead (PAIR_HL, ic))
12592     {
12593       _push (PAIR_HL);
12594       saved_HL = TRUE;
12595     }
12596   if (!isPairDead (PAIR_BC, ic))
12597     {
12598       _push (PAIR_BC);
12599       saved_BC = TRUE;
12600     }
12601   if (!isPairDead (PAIR_DE, ic))
12602     {
12603       _push (PAIR_DE);
12604       saved_DE = TRUE;
12605     }
12606 
12607   setupForMemcpy (ic, dst, src);
12608 
12609   emit3 (A_XOR, ASMOP_A, ASMOP_A);
12610   if (SomethingReturned)
12611     _push (PAIR_DE);
12612   if (!regalloc_dry_run)
12613     {
12614       symbol *tlbl = newiTempLabel (NULL);
12615       emitLabel (tlbl);
12616       emit2 ("cp a, (hl)");
12617       emit2 ("ldi");
12618       emit2 ("jr NZ, !tlabel", labelKey2num (tlbl->key));
12619     }
12620   regalloc_dry_run_cost += 5;
12621 
12622   spillPair (PAIR_HL);
12623 
12624   if (SomethingReturned)
12625     aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12626 
12627   if (!SomethingReturned || SomethingReturned && getPairId (AOP (IC_RESULT (ic))) != PAIR_INVALID)
12628     {
12629       if (SomethingReturned)
12630         _pop (getPairId (AOP (IC_RESULT (ic))));
12631       if (saved_DE)
12632         _pop (PAIR_DE);
12633       if (saved_BC)
12634         _pop (PAIR_BC);
12635       if (saved_HL)
12636         _pop (PAIR_HL);
12637     }
12638   else
12639     {
12640       _pop (PAIR_HL);
12641       assignResultValue (IC_RESULT (ic));
12642 
12643       restoreRegs (0, saved_DE, saved_BC, saved_HL, IC_RESULT (ic));
12644     }
12645 
12646   if (SomethingReturned)
12647     freeAsmop (IC_RESULT (ic), NULL);
12648   freeAsmop (src, NULL);
12649   freeAsmop (dst, NULL);
12650 }
12651 
12652 static void
genBuiltInStrncpy(const iCode * ic,int nparams,operand ** pparams)12653 genBuiltInStrncpy (const iCode *ic, int nparams, operand **pparams)
12654 {
12655   int i;
12656   operand *s1, *s2, *n;
12657   bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
12658 
12659   for (i = 0; i < nparams; i++)
12660     aopOp (pparams[i], ic, FALSE, FALSE);
12661 
12662   wassertl (!IS_GB, "Built-in strncpy() not available on gbz80.");
12663   wassertl (nparams == 3, "Built-in strncpy() must have three parameters.");
12664   wassertl (AOP_TYPE (pparams[2]) == AOP_LIT, "Last parameter to builtin strncpy() must be literal.");
12665 
12666   s1 = pparams[0];
12667   s2 = pparams[1];
12668   n = pparams[2];
12669 
12670   if (!ulFromVal (AOP (n)->aopu.aop_lit))
12671     goto done;
12672 
12673   if (!isPairDead (PAIR_HL, ic))
12674     {
12675       _push (PAIR_HL);
12676       saved_HL = TRUE;
12677     }
12678   if (!isPairDead (PAIR_BC, ic))
12679     {
12680       _push (PAIR_BC);
12681       saved_BC = TRUE;
12682     }
12683   if (!isPairDead (PAIR_DE, ic))
12684     {
12685       _push (PAIR_DE);
12686       saved_DE = TRUE;
12687     }
12688 
12689   setupForMemcpy (ic, s1, s2);
12690 
12691   fetchPair (PAIR_BC, AOP (n));
12692 
12693   emit3 (A_XOR, ASMOP_A, ASMOP_A);
12694   if (!regalloc_dry_run)
12695     {
12696       symbol *tlbl1 = newiTempLabel (0);
12697       symbol *tlbl2 = newiTempLabel (0);
12698       symbol *tlbl3 = newiTempLabel (0);
12699       emitLabel (tlbl2);
12700       emit2 ("cp a, (hl)");
12701       emit2 ("ldi");
12702       emit2 (IS_RAB ? "jp LZ, !tlabel" : "jp PO, !tlabel", labelKey2num (tlbl1->key));
12703       emit2 ("jr NZ, !tlabel", labelKey2num (tlbl2->key));
12704       emitLabel (tlbl3);
12705       emit2 ("dec hl");
12706       emit2 ("ldi");
12707       emit2 (IS_RAB ? "jp LO, !tlabel" : "jp PE, !tlabel", labelKey2num (tlbl3->key));
12708       emitLabel (tlbl1);
12709     }
12710   regalloc_dry_run_cost += 14;
12711 
12712   spillPair (PAIR_HL);
12713 
12714   restoreRegs (0, saved_DE, saved_BC, saved_HL, 0);
12715 
12716 done:
12717   freeAsmop (n, NULL);
12718   freeAsmop (s2, NULL);
12719   freeAsmop (s1, NULL);
12720 }
12721 
12722 static void
genBuiltInStrchr(const iCode * ic,int nParams,operand ** pparams)12723 genBuiltInStrchr (const iCode *ic, int nParams, operand **pparams)
12724 {
12725   operand *s, *c;
12726   bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
12727   int i;
12728   bool SomethingReturned;
12729   PAIR_ID pair;
12730   bool direct_c;
12731   asmop *aop_c;
12732   symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel(0);
12733   symbol *tlbl2 = regalloc_dry_run ? 0 : newiTempLabel(0);
12734 
12735   SomethingReturned = (IS_ITEMP (IC_RESULT (ic)) &&
12736                       (OP_SYMBOL (IC_RESULT (ic))->nRegs ||
12737                       OP_SYMBOL (IC_RESULT (ic))->spildir ||
12738                       OP_SYMBOL (IC_RESULT (ic))->accuse == ACCUSE_A)) || IS_TRUE_SYMOP (IC_RESULT (ic));
12739 
12740   wassertl (nParams == 2, "Built-in strchr() must have two parameters.");
12741 
12742   s = pparams[0];
12743   c = pparams[1];
12744 
12745   for (i = 0; i < nParams; i++)
12746     aopOp (pparams[i], ic, FALSE, FALSE);
12747 
12748   if (SomethingReturned)
12749     aopOp (IC_RESULT (ic), ic, FALSE, FALSE);
12750 
12751   if (getPairId (AOP (s)) != PAIR_INVALID && getPairId (AOP (s)) != PAIR_IY)
12752     pair = getPairId (AOP (s));
12753   else if (SomethingReturned && getPairId (AOP (IC_RESULT (ic))) != PAIR_INVALID && getPairId (AOP (IC_RESULT (ic))) != PAIR_IY)
12754     pair = getPairId (AOP (IC_RESULT (ic)));
12755   else
12756     pair = PAIR_HL;
12757 
12758   if (AOP_TYPE (c) == AOP_REG && AOP (c)->aopu.aop_reg[0]->rIdx != IYL_IDX && AOP (c)->aopu.aop_reg[0]->rIdx != IYH_IDX &&
12759     !(pair == PAIR_HL && (AOP (c)->aopu.aop_reg[0]->rIdx == L_IDX || AOP (c)->aopu.aop_reg[0]->rIdx == H_IDX)) &&
12760     !(pair == PAIR_DE && (AOP (c)->aopu.aop_reg[0]->rIdx == E_IDX || AOP (c)->aopu.aop_reg[0]->rIdx == D_IDX)) &&
12761     !(pair == PAIR_BC && (AOP (c)->aopu.aop_reg[0]->rIdx == B_IDX || AOP (c)->aopu.aop_reg[0]->rIdx == C_IDX)))
12762     direct_c = TRUE;
12763   else if (AOP_TYPE (c) == AOP_LIT && optimize.codeSize)
12764     direct_c = TRUE;
12765   else
12766     direct_c = FALSE;
12767 
12768   aop_c = direct_c ? AOP (c) : (pair == PAIR_DE ? ASMOP_H : ASMOP_D);
12769 
12770   if ((pair == PAIR_HL || pair == PAIR_DE && !direct_c) && !isPairDead (PAIR_HL, ic))
12771     {
12772       _push (PAIR_HL);
12773       saved_HL = TRUE;
12774     }
12775   if (pair == PAIR_BC && !isPairDead (PAIR_BC, ic))
12776     {
12777       _push (PAIR_BC);
12778       saved_BC = TRUE;
12779     }
12780   if ((pair == PAIR_DE || !direct_c) && !isPairDead (PAIR_DE, ic))
12781     {
12782       _push (PAIR_DE);
12783       saved_DE = TRUE;
12784     }
12785 
12786   if (!direct_c)
12787     cheapMove (aop_c, 0, AOP (c), 0, true);
12788   fetchPair (pair, AOP (s));
12789 
12790   if (!regalloc_dry_run)
12791     emitLabel (tlbl2);
12792   emit2 ("ld a, (%s)", _pairs[pair].name);
12793   regalloc_dry_run_cost++;
12794   emit3 (A_CP, ASMOP_A, aop_c);
12795   if (!regalloc_dry_run)
12796     emit2 ("jp Z, !tlabel", labelKey2num (tlbl1->key));
12797   emit2 ("or a, a");
12798   emit2 ("inc %s", _pairs[pair].name);
12799   if (!regalloc_dry_run)
12800     emit2 ("jr NZ, !tlabel", labelKey2num (tlbl2->key));
12801   emit2 ("ld %s, a", _pairs[pair].l);
12802   emit2 ("ld %s, a", _pairs[pair].h);
12803   regalloc_dry_run_cost += 8; // jp will most likely be optimized into jr.
12804   if (!regalloc_dry_run)
12805     emitLabel (tlbl1);
12806   if (SomethingReturned)
12807     commitPair (AOP (IC_RESULT (ic)), pair, ic, FALSE);
12808 
12809   restoreRegs (0, saved_DE, saved_BC, saved_HL, SomethingReturned ? IC_RESULT (ic) : 0);
12810 
12811   if (SomethingReturned)
12812     freeAsmop (IC_RESULT (ic), NULL);
12813   freeAsmop (c, NULL);
12814   freeAsmop (s, NULL);
12815 }
12816 
12817 /*-----------------------------------------------------------------*/
12818 /* genBuiltIn - calls the appropriate function to generate code    */
12819 /* for a built in function                                         */
12820 /*-----------------------------------------------------------------*/
12821 static void
genBuiltIn(iCode * ic)12822 genBuiltIn (iCode *ic)
12823 {
12824   operand *bi_parms[MAX_BUILTIN_ARGS];
12825   int nbi_parms;
12826   iCode *bi_iCode;
12827   symbol *bif;
12828 
12829   /* get all the arguments for a built in function */
12830   bi_iCode = getBuiltinParms (ic, &nbi_parms, bi_parms);
12831 
12832   /* which function is it */
12833   bif = OP_SYMBOL (IC_LEFT (bi_iCode));
12834 
12835   wassertl (!ic->prev || ic->prev->op != SEND || !ic->prev->builtinSEND, "genBuiltIn() must be called on first SEND icode only.");
12836 
12837   if (!strcmp (bif->name, "__builtin_memcpy"))
12838     {
12839       genBuiltInMemcpy (bi_iCode, nbi_parms, bi_parms);
12840     }
12841   else if (!strcmp (bif->name, "__builtin_strcpy"))
12842     {
12843       genBuiltInStrcpy (bi_iCode, nbi_parms, bi_parms);
12844     }
12845   else if (!strcmp (bif->name, "__builtin_strncpy"))
12846     {
12847       genBuiltInStrncpy (bi_iCode, nbi_parms, bi_parms);
12848     }
12849   else if (!strcmp (bif->name, "__builtin_strchr"))
12850     {
12851       genBuiltInStrchr (bi_iCode, nbi_parms, bi_parms);
12852     }
12853   else if (!strcmp (bif->name, "__builtin_memset"))
12854     {
12855       genBuiltInMemset (bi_iCode, nbi_parms, bi_parms);
12856     }
12857   else
12858     {
12859       wassertl (0, "Unknown builtin function encountered");
12860     }
12861 }
12862 
12863 /*-------------------------------------------------------------------------------------*/
12864 /* genZ80iCode - generate code for Z80 based controllers for a single iCode instruction*/
12865 /*-------------------------------------------------------------------------------------*/
12866 static void
genZ80iCode(iCode * ic)12867 genZ80iCode (iCode * ic)
12868 {
12869   genLine.lineElement.ic = ic;
12870 
12871   /* if the result is marked as
12872      spilt and rematerializable or code for
12873      this has already been generated then
12874      do nothing */
12875   if (resultRemat (ic) || ic->generated)
12876     return;
12877 
12878   /* depending on the operation */
12879   switch (ic->op)
12880     {
12881     case '!':
12882       emitDebug ("; genNot");
12883       genNot (ic);
12884       break;
12885 
12886     case '~':
12887       emitDebug ("; genCpl");
12888       genCpl (ic);
12889       break;
12890 
12891     case UNARYMINUS:
12892       emitDebug ("; genUminus");
12893       genUminus (ic);
12894       break;
12895 
12896     case IPUSH:
12897       emitDebug ("; genIpush");
12898       genIpush (ic);
12899       break;
12900 
12901     case IPOP:
12902       /* IPOP happens only when trying to restore a
12903          spilt live range, if there is an ifx statement
12904          following this pop then the if statement might
12905          be using some of the registers being popped which
12906          would destroy the contents of the register so
12907          we need to check for this condition and handle it */
12908       if (ic->next && ic->next->op == IFX && regsInCommon (IC_LEFT (ic), IC_COND (ic->next)))
12909         {
12910           emitDebug ("; genIfx");
12911           genIfx (ic->next, ic);
12912         }
12913       else
12914         {
12915           emitDebug ("; genIpop");
12916           genIpop (ic);
12917         }
12918       break;
12919 
12920     case CALL:
12921     case PCALL:
12922       emitDebug ("; genCall");
12923       genCall (ic);
12924       break;
12925 
12926     case FUNCTION:
12927       emitDebug ("; genFunction");
12928       genFunction (ic);
12929       break;
12930 
12931     case ENDFUNCTION:
12932       emitDebug ("; genEndFunction");
12933       genEndFunction (ic);
12934       break;
12935 
12936     case RETURN:
12937       emitDebug ("; genRet");
12938       genRet (ic);
12939       break;
12940 
12941     case LABEL:
12942       emitDebug ("; genLabel");
12943       genLabel (ic);
12944       break;
12945 
12946     case GOTO:
12947       emitDebug ("; genGoto");
12948       genGoto (ic);
12949       break;
12950 
12951     case '+':
12952       emitDebug ("; genPlus");
12953       genPlus (ic);
12954       break;
12955 
12956     case '-':
12957       emitDebug ("; genMinus");
12958       genMinus (ic);
12959       break;
12960 
12961     case '*':
12962       emitDebug ("; genMult");
12963       genMult (ic);
12964       break;
12965 
12966     case '/':
12967       emitDebug ("; genDiv");
12968       genDiv (ic);
12969       break;
12970 
12971     case '%':
12972       emitDebug ("; genMod");
12973       genMod (ic);
12974       break;
12975 
12976     case '>':
12977       emitDebug ("; genCmpGt");
12978       genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
12979       break;
12980 
12981     case '<':
12982       emitDebug ("; genCmpLt");
12983       genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
12984       break;
12985 
12986     case LE_OP:
12987     case GE_OP:
12988     case NE_OP:
12989 
12990       /* note these two are xlated by algebraic equivalence
12991          during parsing SDCC.y */
12992       werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got '>=' or '<=' shouldn't have come here");
12993       break;
12994 
12995     case EQ_OP:
12996       emitDebug ("; genCmpEq");
12997       genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
12998       break;
12999 
13000     case AND_OP:
13001       emitDebug ("; genAndOp");
13002       genAndOp (ic);
13003       break;
13004 
13005     case OR_OP:
13006       emitDebug ("; genOrOp");
13007       genOrOp (ic);
13008       break;
13009 
13010     case '^':
13011       emitDebug ("; genXor");
13012       genXor (ic, ifxForOp (IC_RESULT (ic), ic));
13013       break;
13014 
13015     case '|':
13016       emitDebug ("; genOr");
13017       genOr (ic, ifxForOp (IC_RESULT (ic), ic));
13018       break;
13019 
13020     case BITWISEAND:
13021       emitDebug ("; genAnd");
13022       genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
13023       break;
13024 
13025     case INLINEASM:
13026       emitDebug ("; genInline");
13027       genInline (ic);
13028       break;
13029 
13030     case RRC:
13031       emitDebug ("; genRRC");
13032       genRRC (ic);
13033       break;
13034 
13035     case RLC:
13036       emitDebug ("; genRLC");
13037       genRLC (ic);
13038       break;
13039 
13040     case GETHBIT:
13041       emitDebug ("; genGetHbit");
13042       genGetHbit (ic);
13043       break;
13044 
13045     case GETABIT:
13046       emitDebug ("; genGetAbit");
13047       genGetAbit (ic);
13048       break;
13049 
13050     case LEFT_OP:
13051       emitDebug ("; genLeftShift");
13052       genLeftShift (ic);
13053       break;
13054 
13055     case RIGHT_OP:
13056       emitDebug ("; genRightShift");
13057       genRightShift (ic);
13058       break;
13059 
13060     case GET_VALUE_AT_ADDRESS:
13061       emitDebug ("; genPointerGet");
13062       genPointerGet (ic);
13063       break;
13064 
13065     case '=':
13066 
13067       if (POINTER_SET (ic))
13068         {
13069           emitDebug ("; genAssign (pointer)");
13070           genPointerSet (ic);
13071         }
13072       else
13073         {
13074           emitDebug ("; genAssign");
13075           genAssign (ic);
13076         }
13077       break;
13078 
13079     case IFX:
13080       emitDebug ("; genIfx");
13081       genIfx (ic, NULL);
13082       break;
13083 
13084     case ADDRESS_OF:
13085       emitDebug ("; genAddrOf");
13086       genAddrOf (ic);
13087       break;
13088 
13089     case JUMPTABLE:
13090       emitDebug ("; genJumpTab");
13091       genJumpTab (ic);
13092       break;
13093 
13094     case CAST:
13095       emitDebug ("; genCast");
13096       genCast (ic);
13097       break;
13098 
13099     case RECEIVE:
13100       emitDebug ("; genReceive");
13101       genReceive (ic);
13102       break;
13103 
13104     case SEND:
13105       if (ic->builtinSEND)
13106         {
13107           emitDebug ("; genBuiltIn");
13108           genBuiltIn (ic);
13109         }
13110       else
13111         {
13112           emitDebug ("; genSend");
13113           genSend (ic);
13114         }
13115       break;
13116 
13117 #if 0
13118     case ARRAYINIT:
13119       emitDebug ("; genArrayInit");
13120       genArrayInit (ic);
13121       break;
13122 #endif
13123 
13124     case DUMMY_READ_VOLATILE:
13125       emitDebug ("; genDummyRead");
13126       genDummyRead (ic);
13127       break;
13128 
13129     case CRITICAL:
13130       emitDebug ("; genCritical");
13131       genCritical (ic);
13132       break;
13133 
13134     case ENDCRITICAL:
13135       emitDebug ("; genEndCritical");
13136       genEndCritical (ic);
13137       break;
13138 
13139     default:
13140       ;
13141     }
13142 }
13143 
13144 unsigned char
dryZ80iCode(iCode * ic)13145 dryZ80iCode (iCode * ic)
13146 {
13147   regalloc_dry_run = TRUE;
13148   regalloc_dry_run_cost = 0;
13149 
13150   initGenLineElement ();
13151   _G.omitFramePtr = should_omit_frame_ptr;
13152 
13153   genZ80iCode (ic);
13154 
13155   destroy_line_list ();
13156   freeTrace (&_G.trace.aops);
13157 
13158   {
13159     int pairId;
13160     for (pairId = 0; pairId < NUM_PAIRS; pairId++)
13161       spillPair (pairId);
13162   }
13163 
13164   return (regalloc_dry_run_cost);
13165 }
13166 
13167 #ifdef DEBUG_DRY_COST
13168 static void
dryZ80Code(iCode * lic)13169 dryZ80Code (iCode * lic)
13170 {
13171   iCode *ic;
13172 
13173   for (ic = lic; ic; ic = ic->next)
13174     if (ic->op != FUNCTION && ic->op != ENDFUNCTION && ic->op != LABEL && ic->op != GOTO && ic->op != INLINEASM)
13175       printf ("; iCode %d total cost: %d\n", ic->key, (int) (dryZ80iCode (ic)));
13176 }
13177 #endif
13178 
13179 /*-------------------------------------------------------------------------------------*/
13180 /* genZ80Code - generate code for Z80 based controllers for a block of intructions     */
13181 /*-------------------------------------------------------------------------------------*/
13182 void
genZ80Code(iCode * lic)13183 genZ80Code (iCode * lic)
13184 {
13185 #ifdef DEBUG_DRY_COST
13186   dryZ80Code (lic);
13187 #endif
13188 
13189   iCode *ic;
13190   int cln = 0;
13191   regalloc_dry_run = FALSE;
13192 
13193   initGenLineElement ();
13194 
13195   memset(z80_regs_used_as_parms_in_calls_from_current_function, 0, sizeof(bool) * (IYH_IDX + 1));
13196   z80_symmParm_in_calls_from_current_function = TRUE;
13197   memset(z80_regs_preserved_in_calls_from_current_function, 0, sizeof(bool) * (IYH_IDX + 1));
13198 
13199   /* if debug information required */
13200   if (options.debug && currFunc)
13201     {
13202       debugFile->writeFunction (currFunc, lic);
13203     }
13204 
13205   for (ic = lic; ic; ic = ic->next)
13206     ic->generated = FALSE;
13207 
13208   /* Generate Code for all instructions */
13209   for (ic = lic; ic; ic = ic->next)
13210     {
13211       if (ic->lineno && cln != ic->lineno)
13212         {
13213           if (options.debug)
13214             debugFile->writeCLine (ic);
13215           if (!options.noCcodeInAsm)
13216             emit2 (";%s:%d: %s", ic->filename, ic->lineno, printCLine (ic->filename, ic->lineno));
13217           cln = ic->lineno;
13218         }
13219       if (options.iCodeInAsm)
13220         {
13221           const char *iLine = printILine (ic);
13222           emit2 (";ic:%d: %s", ic->key, iLine);
13223           dbuf_free (iLine);
13224         }
13225       regalloc_dry_run_cost = 0;
13226       genZ80iCode (ic);
13227 
13228 #ifdef DEBUG_DRY_COST
13229       emit2 ("; iCode %d total cost: %d\n", ic->key, regalloc_dry_run_cost);
13230 #endif
13231     }
13232 
13233   /* now we are ready to call the
13234      peep hole optimizer */
13235   if (!options.nopeep)
13236     peepHole (&genLine.lineHead);
13237 
13238   /* This is unfortunate */
13239   /* now do the actual printing */
13240   {
13241     struct dbuf_s *buf = codeOutBuf;
13242     if (isInHome () && codeOutBuf == &code->oBuf)
13243       codeOutBuf = &home->oBuf;
13244     printLine (genLine.lineHead, codeOutBuf);
13245     if (_G.flushStatics)
13246       {
13247         flushStatics ();
13248         _G.flushStatics = 0;
13249       }
13250     codeOutBuf = buf;
13251   }
13252 
13253   {
13254     int pairId;
13255     for (pairId = 0; pairId < NUM_PAIRS; pairId++)
13256       spillPair (pairId);
13257   }
13258 
13259   destroy_line_list ();
13260   freeTrace (&_G.trace.aops);
13261 }
13262 
13263