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