Pick three bugfixes from next branch to trunk for inclusion in 4.5.0 RC2, as discusse...
[sdcc.git] / sdcc / src / z80 / gen.c
blobe54c4a56f5bb83935d8c7f14822d7e4956ae46de
1 /*-------------------------------------------------------------------------
2 gen.c - code generator for Z80 and related.
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-2024, Philipp Klaus Krause pkk@spth.de, philipp@informatik.uni-frankfurt.de, philipp@colecovision.eu)
8 Copyright (C) 2021-2022, Sebastian 'basxto' Riedel <sdcc@basxto.de>
10 This program is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License as published by the
12 Free Software Foundation; either version 2, or (at your option) any
13 later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 -------------------------------------------------------------------------*/
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
30 #include "z80.h"
31 #include "gen.h"
32 #include "dbuf_string.h"
34 /* This is the down and dirty file with all kinds of kludgy & hacky
35 stuff. This is what it is all about CODE GENERATION for a specific MCU.
36 Some of the routines may be reusable, will have to see */
38 enum
40 /* Set to enable debugging trace statements in the output assembly code. */
41 DISABLE_DEBUG = 0
44 #define UNIMPLEMENTED do {wassertl (regalloc_dry_run, "Unimplemented"); cost (4000, 4000.0f);} while(0)
46 #undef DEBUG_DRY_COST
48 extern struct dbuf_s *codeOutBuf;
50 enum
52 INT8MIN = -128,
53 INT8MAX = 127
56 /** Enum covering all the possible register pairs.
58 typedef enum
60 PAIR_INVALID,
61 PAIR_AF,
62 PAIR_BC,
63 PAIR_DE,
64 PAIR_HL,
65 PAIR_IY,
66 PAIR_IX,
67 NUM_PAIRS
68 } PAIR_ID;
70 static struct
72 const char *name;
73 const char *l;
74 const char *h;
75 int l_idx;
76 int h_idx;
77 } _pairs[NUM_PAIRS] =
80 "??1", "?2", "?3", -1, -1
83 "af", "f", "a", -1, A_IDX
86 "bc", "c", "b", C_IDX, B_IDX
89 "de", "e", "d", E_IDX, D_IDX
92 "hl", "l", "h", L_IDX, H_IDX
95 "iy", "iyl", "iyh", IYL_IDX, IYH_IDX
98 "ix", "ixl", "ixh", -1, -1
102 enum
104 LSB,
105 MSB16,
106 MSB24,
107 MSB32
110 enum asminst
112 A_ADD,
113 A_ADC,
114 A_AND,
115 A_CP,
116 A_CPL,
117 A_DEC,
118 A_EX,
119 A_INC,
120 A_LD,
121 A_NEG,
122 A_OR,
123 A_RL,
124 A_RLA,
125 A_RLC,
126 A_RLCA,
127 A_RLD,
128 A_RR,
129 A_RRA,
130 A_RRC,
131 A_RRCA,
132 A_RRD,
133 A_SBC,
134 A_SLA,
135 A_SRA,
136 A_SRL,
137 A_SUB,
138 A_XOR,
139 A_SWAP
142 static const char *asminstnames[] =
144 "add",
145 "adc",
146 "and",
147 "cp",
148 "cpl",
149 "dec",
150 "ex",
151 "inc",
152 "ld",
153 "neg",
154 "or",
155 "rl",
156 "rla",
157 "rlc",
158 "rlca",
159 "rld",
160 "rr",
161 "rra",
162 "rrc",
163 "rrca",
164 "rrd",
165 "sbc",
166 "sla",
167 "sra",
168 "srl",
169 "sub",
170 "xor",
171 "swap"
174 /** Code generator persistent data.
176 static struct
178 /** Used to optimise setting up of a pair by remembering what it
179 contains and adjusting instead of reloading where possible.
181 struct
183 AOP_TYPE last_type;
184 const char *base; // For addresses
185 unsigned int value; // For AOP_LIT
186 int offset;
187 } pairs[NUM_PAIRS];
188 struct
190 // int last;
191 int pushed;
192 int param_offset;
193 int offset;
194 int pushedHL;
195 int pushedBC;
196 int pushedDE;
197 int pushedIY;
198 } stack;
200 struct
202 int pushedBC;
203 int pushedDE;
204 } calleeSaves;
206 bool omitFramePtr;
207 int frameId;
208 int receiveOffset;
209 bool flushStatics;
210 bool in_home;
211 const char *lastFunctionName;
212 iCode *current_iCode;
213 bool preserveCarry;
215 set *sendSet;
217 struct
219 /** TRUE if the registers have already been saved. */
220 bool saved;
221 } saves;
223 struct
225 allocTrace trace;
226 } lines;
228 struct
230 allocTrace aops;
231 } trace;
232 } _G;
234 bool z80_regs_used_as_parms_in_calls_from_current_function[IYH_IDX + 1];
235 bool z80_symmParm_in_calls_from_current_function;
236 bool z80_regs_preserved_in_calls_from_current_function[IYH_IDX + 1];
238 static const char *aopGet (asmop *aop, int offset, bool bit16);
240 static struct asmop asmop_a, asmop_b, asmop_c, asmop_d, asmop_e, asmop_h, asmop_l, asmop_iyh, asmop_iyl, asmop_hl, asmop_de, asmop_bc, asmop_iy, asmop_dehl, asmop_hlde, asmop_hlbc, asmop_debc, asmop_zero, asmop_one, asmop_mone;
241 static struct asmop *const ASMOP_A = &asmop_a;
242 static struct asmop *const ASMOP_B = &asmop_b;
243 static struct asmop *const ASMOP_C = &asmop_c;
244 static struct asmop *const ASMOP_D = &asmop_d;
245 static struct asmop *const ASMOP_E = &asmop_e;
246 static struct asmop *const ASMOP_H = &asmop_h;
247 static struct asmop *const ASMOP_L = &asmop_l;
248 static struct asmop *const ASMOP_IYH = &asmop_iyh;
249 static struct asmop *const ASMOP_IYL = &asmop_iyl;
250 static struct asmop *const ASMOP_HL = &asmop_hl;
251 static struct asmop *const ASMOP_DE = &asmop_de;
252 static struct asmop *const ASMOP_BC = &asmop_bc;
253 static struct asmop *const ASMOP_IY = &asmop_iy;
254 static struct asmop *const ASMOP_DEHL = &asmop_dehl;
255 static struct asmop *const ASMOP_HLDE = &asmop_hlde;
256 static struct asmop *const ASMOP_HLBC = &asmop_hlbc;
257 static struct asmop *const ASMOP_DEBC = &asmop_debc;
258 static struct asmop *const ASMOP_ZERO = &asmop_zero;
259 static struct asmop *const ASMOP_ONE = &asmop_one;
260 static struct asmop *const ASMOP_MONE = &asmop_mone;
262 static asmop *asmopregs[] = { &asmop_a, &asmop_c, &asmop_b, &asmop_e, &asmop_d, &asmop_l, &asmop_h, &asmop_iyl, &asmop_iyh };
264 // Init aop as a an asmop for data in registers, as given by the -1-terminated array regidx.
265 static void
266 z80_init_reg_asmop(asmop *aop, const signed char *regidx)
268 aop->type = AOP_REG;
269 aop->size = 0;
270 memset (aop->regs, -1, sizeof(aop->regs));
272 for(int i = 0; regidx[i] >= 0; i++)
274 aop->aopu.aop_reg[i] = regsZ80 + regidx[i];
275 aop->regs[regidx[i]] = i;
276 aop->size++;
279 aop->valinfo.anything = true;
282 void
283 z80_init_asmops (void)
285 z80_init_reg_asmop(&asmop_a, (const signed char[]){A_IDX, -1});
286 z80_init_reg_asmop(&asmop_b, (const signed char[]){B_IDX, -1});
287 z80_init_reg_asmop(&asmop_c, (const signed char[]){C_IDX, -1});
288 z80_init_reg_asmop(&asmop_d, (const signed char[]){D_IDX, -1});
289 z80_init_reg_asmop(&asmop_e, (const signed char[]){E_IDX, -1});
290 z80_init_reg_asmop(&asmop_h, (const signed char[]){H_IDX, -1});
291 z80_init_reg_asmop(&asmop_l, (const signed char[]){L_IDX, -1});
292 z80_init_reg_asmop(&asmop_iyh, (const signed char[]){IYH_IDX, -1});
293 z80_init_reg_asmop(&asmop_iyl, (const signed char[]){IYL_IDX, -1});
294 z80_init_reg_asmop(&asmop_bc, (const signed char[]){C_IDX, B_IDX, -1});
295 z80_init_reg_asmop(&asmop_de, (const signed char[]){E_IDX, D_IDX, -1});
296 z80_init_reg_asmop(&asmop_hl, (const signed char[]){L_IDX, H_IDX, -1});
297 z80_init_reg_asmop(&asmop_dehl, (const signed char[]){L_IDX, H_IDX, E_IDX, D_IDX, -1});
298 z80_init_reg_asmop(&asmop_hlde, (const signed char[]){E_IDX, D_IDX, L_IDX, H_IDX, -1});
299 z80_init_reg_asmop(&asmop_iy, (const signed char[]){IYL_IDX, IYH_IDX, -1});
300 z80_init_reg_asmop(&asmop_hlbc, (const signed char[]){C_IDX, B_IDX, L_IDX, H_IDX, -1});
301 z80_init_reg_asmop(&asmop_debc, (const signed char[]){C_IDX, B_IDX, E_IDX, D_IDX, -1});
303 asmop_zero.type = AOP_LIT;
304 asmop_zero.aopu.aop_lit = constVal ("0");
305 asmop_zero.size = 1;
306 memset (asmop_zero.regs, -1, 9);
307 asmop_zero.valinfo.anything = true;
309 asmop_one.type = AOP_LIT;
310 asmop_one.aopu.aop_lit = constVal ("1");
311 asmop_one.size = 1;
312 memset (asmop_one.regs, -1, 9);
313 asmop_one.valinfo.anything = true;
315 asmop_mone.type = AOP_LIT;
316 asmop_mone.aopu.aop_lit = constVal ("-1");
317 asmop_mone.size = 1;
318 memset (asmop_mone.regs, -1, 9);
319 asmop_mone.valinfo.anything = true;
322 static bool regalloc_dry_run;
323 static unsigned int regalloc_dry_run_cost; // Legacy: cost counted in bytes only (i.e. states have been ignored for corresponding instructions).
324 static unsigned long regalloc_dry_run_cost_bytes;
325 static float regalloc_dry_run_cost_states;
326 static float regalloc_dry_run_state_scale = 1.0f;
328 static void
329 cost (unsigned int bytes, float states)
331 regalloc_dry_run_cost_bytes += bytes;
332 regalloc_dry_run_cost_states += states * regalloc_dry_run_state_scale;
335 static void
336 cost2 (unsigned int bytes, unsigned int z80_states /* also z80n */, unsigned int z180_states, unsigned int r2k_clocks, unsigned int sm83_cycles, unsigned int tlcs90_states, unsigned int ez80_z80_cycles, unsigned int r800_cycles)
338 regalloc_dry_run_cost_bytes += bytes;
339 if (IS_Z80 || IS_Z80N)
340 regalloc_dry_run_cost_states += z80_states * regalloc_dry_run_state_scale;
341 else if (IS_Z180)
342 regalloc_dry_run_cost_states += z180_states * regalloc_dry_run_state_scale;
343 else if (IS_RAB)
344 regalloc_dry_run_cost_states += r2k_clocks * regalloc_dry_run_state_scale;
345 else if (IS_SM83)
346 regalloc_dry_run_cost_states += sm83_cycles * regalloc_dry_run_state_scale;
347 else if(IS_TLCS90)
348 regalloc_dry_run_cost_states += tlcs90_states * regalloc_dry_run_state_scale;
349 else if(IS_EZ80_Z80)
350 regalloc_dry_run_cost_states += ez80_z80_cycles * regalloc_dry_run_state_scale;
351 else if(IS_R800)
352 regalloc_dry_run_cost_states += r800_cycles * regalloc_dry_run_state_scale;
353 else
354 wassert (0);
357 /*-----------------------------------------------------------------*/
358 /* isRegIdxPair - true, if specified index is register pair, */
359 /* rIdx changed to index of lower register */
360 /*-----------------------------------------------------------------*/
361 static bool
362 isRegIdxPair (short *rIdx)
364 switch (*rIdx)
366 case BC_IDX:
367 *rIdx = C_IDX;
368 break;
369 case DE_IDX:
370 *rIdx = E_IDX;
371 break;
372 case HL_IDX:
373 *rIdx = L_IDX;
374 break;
375 case IY_IDX:
376 *rIdx = IYL_IDX;
377 break;
378 default:
379 return false;
381 return true;
384 /*-----------------------------------------------------------------*/
385 /* aopRegOffset - return register offset in the asmop */
386 /*-----------------------------------------------------------------*/
387 static int
388 aopRegOffset (const asmop *aop, short rIdx)
390 if (rIdx < 0 || aop->type != AOP_REG)
391 return -1;
393 if (!isRegIdxPair (&rIdx))
394 return aop->regs[rIdx];
396 int offset = aop->regs[rIdx];
397 return (offset != -1 && aop->regs[rIdx+1] == offset+1) ? offset : -1;
400 /*-----------------------------------------------------------------*/
401 /* aopUseReg - return true if register is in the asmop */
402 /*-----------------------------------------------------------------*/
403 static inline bool
404 aopRegUsed (const asmop *aop, short rIdx)
406 if (aop->type != AOP_REG)
407 return false;
409 if (!isRegIdxPair (&rIdx))
410 return aop->regs[rIdx];
412 return aop->regs[rIdx] != -1 || aop->regs[rIdx+1] != -1;
415 /*-----------------------------------------------------------------*/
416 /* aopRegUsedRange - true if register is in specified position range [minPos;maxPos) */
417 /*-----------------------------------------------------------------*/
418 static inline bool
419 aopRegUsedRange (const asmop *aop, short rIdx, int minPos, int maxPos)
421 if (aop->type != AOP_REG)
422 return false;
424 if (!isRegIdxPair (&rIdx))
425 return aop->regs[rIdx] >= minPos && aop->regs[rIdx] < maxPos;
427 return (aop->regs[rIdx] >= minPos && aop->regs[rIdx] < maxPos) ||
428 (aop->regs[rIdx+1] >= minPos && aop->regs[rIdx+1] < maxPos);
431 /*-----------------------------------------------------------------*/
432 /* aopRS - asmop in register or on stack. */
433 /*-----------------------------------------------------------------*/
434 static bool
435 aopRS (const asmop *aop)
437 return (aop->type == AOP_REG || aop->type == AOP_STK || aop->type == AOP_EXSTK);
440 /*-----------------------------------------------------------------*/
441 /* aopIsLitVal - asmop from offset is val. */
442 /* False negatives are possible. */
443 /*-----------------------------------------------------------------*/
444 static bool
445 aopIsLitVal (const asmop *aop, int offset, int size, unsigned long long int val)
447 wassert (size <= sizeof (unsigned long long int)); // Make sure we are not testing outside of argument val.
449 for(; size; size--, offset++)
451 unsigned char b = val & 0xff;
452 val >>= 8;
454 // Leading zeroes
455 if (aop->size <= offset && !b && aop->type != AOP_LIT)
456 continue;
458 // Information from generalized constant propagation analysis
459 if (!aop->valinfo.anything && offset < 8 &&
460 ((aop->valinfo.knownbitsmask >> (offset * 8)) & 0xff) == 0xff &&
461 ((aop->valinfo.knownbits >> (offset * 8)) & 0xff) == b)
462 continue;
464 if (aop->type != AOP_LIT)
465 return (false);
467 if (byteOfVal (aop->aopu.aop_lit, offset) != b)
468 return (false);
471 return (true);
474 /*-----------------------------------------------------------------*/
475 /* aopIsLitBit - asmop from offset is val. */
476 /* False negatives are possible. */
477 /*-----------------------------------------------------------------*/
478 static bool
479 aopIsLitBit (const asmop *aop, int boffset, bool val)
481 if (!aop->valinfo.anything && boffset < 64 &&
482 ((aop->valinfo.knownbitsmask >> boffset) & 1) &&
483 ((aop->valinfo.knownbits >> boffset) & 1) == val)
484 return(true);
486 return (false);
489 /*-----------------------------------------------------------------*/
490 /* aopIsNotLitVal - asmop from offset is not val. */
491 /* False negatives are possible. */
492 /* Note that both aopIsLitVal and aopIsNotLitVal can be false for */
493 /* same arguments: we might just not have enough information. */
494 /*-----------------------------------------------------------------*/
495 static bool
496 aopIsNotLitVal (const asmop *aop, int offset, int size, unsigned long long int val)
498 wassert (size <= sizeof (unsigned long long int)); // Make sure we are not testing outside of argument val.
500 for(; size; size--, offset++)
502 unsigned char b = val & 0xff;
503 val >>= 8;
505 // Leading zeroes
506 if (aop->size <= offset && b)
507 return (true);
509 // Information from generalized constant propagation analysis
510 if (!aop->valinfo.anything && offset < 8)
512 unsigned char knownbitsmask = aop->valinfo.knownbitsmask >> (offset * 8);
513 unsigned char knownbits = aop->valinfo.knownbits >> (offset * 8);
515 if ((knownbits & knownbitsmask) != (b & knownbitsmask))
516 return (true);
517 if (!offset && aop->valinfo.min > 0 && aop->valinfo.max <= 255 &&
518 (aop->valinfo.min > b || aop->valinfo.min < b))
519 return (true);
522 if (aop->type != AOP_LIT)
523 continue;
525 if (byteOfVal (aop->aopu.aop_lit, offset) != b)
526 return (true);
529 return (false);
532 /*-----------------------------------------------------------------*/
533 /* aopInReg - asmop from offset in the register */
534 /*-----------------------------------------------------------------*/
535 static inline bool
536 aopInReg (const asmop *aop, int offset, short rIdx)
538 if (offset >= aop->size || offset < 0)
539 return (false);
541 return aopRegOffset (aop, rIdx) == offset;
544 /*-----------------------------------------------------------------*/
545 /* aopOnStack - asmop from offset on stack in consecutive memory */
546 /*-----------------------------------------------------------------*/
547 static bool
548 aopOnStack (const asmop *aop, int offset, int size)
550 if (!(aop->type == AOP_STK || aop->type == AOP_EXSTK))
551 return (false);
553 if (offset + size > aop->size)
554 return (false);
556 return (true);
559 static inline int
560 fpOffset (int aop_stk)
562 return aop_stk + (aop_stk > 0 ? _G.stack.param_offset : 0);
565 static int
566 spOffset (int aop_stk)
568 return fpOffset (aop_stk) + _G.stack.pushed + _G.stack.offset;
571 /* WARNING: This function is dangerous to use. It works literally:
572 It will return true if ic the the last use of op, even if ic might
573 be executed again, e.g. due to a loop. Most of the time you will want
574 to use isPairDead(), or ic->rSurv instead of this function. */
575 static bool
576 isLastUse (const iCode * ic, operand * op)
578 bitVect *uses = bitVectCopy (OP_USES (op));
580 while (!bitVectIsZero (uses))
582 if (bitVectFirstBit (uses) == ic->key)
584 if (bitVectnBitsOn (uses) == 1)
586 return TRUE;
588 else
590 return FALSE;
593 bitVectUnSetBit (uses, bitVectFirstBit (uses));
596 return FALSE;
599 static bool
600 isRegDead (short rIdx, const iCode * ic)
602 if (!isRegIdxPair (&rIdx))
603 return !bitVectBitValue (ic->rSurv, rIdx);
604 return !bitVectBitValue (ic->rSurv, rIdx) && !bitVectBitValue (ic->rSurv, rIdx+1);
607 static PAIR_ID
608 _getTempPairId (void)
610 if (IS_SM83)
612 return PAIR_DE;
614 else
616 return PAIR_HL;
620 static const char *
621 _getTempPairName (void)
623 return _pairs[_getTempPairId ()].name;
626 static bool
627 isPairInUse (PAIR_ID id, const iCode * ic)
629 if (id == PAIR_DE)
631 return bitVectBitValue (ic->rMask, D_IDX) || bitVectBitValue (ic->rMask, E_IDX);
633 else if (id == PAIR_BC)
635 return bitVectBitValue (ic->rMask, B_IDX) || bitVectBitValue (ic->rMask, C_IDX);
637 else
639 wassertl (0, "Only implemented for DE and BC");
640 return TRUE;
644 static bool
645 isPairDead (PAIR_ID id, const iCode * ic)
647 switch (id)
649 case PAIR_DE:
650 return isRegDead (D_IDX, ic) && isRegDead (E_IDX, ic);
651 case PAIR_BC:
652 return isRegDead (B_IDX, ic) && isRegDead (C_IDX, ic);
653 case PAIR_HL:
654 return isRegDead (H_IDX, ic) && isRegDead (L_IDX, ic);
655 case PAIR_IY:
656 return isRegDead (IYH_IDX, ic) && isRegDead (IYL_IDX, ic);
657 default:
658 wassertl (0, "Only implemented for DE, BC, HL and IY");
659 return FALSE;
663 static PAIR_ID
664 getDeadPairId (const iCode *ic)
666 if (isPairDead (PAIR_BC, ic))
668 return PAIR_BC;
670 else if (!IS_SM83 && isPairDead (PAIR_DE, ic))
672 return PAIR_DE;
674 else
676 return PAIR_INVALID;
680 static PAIR_ID
681 getFreePairId (const iCode *ic)
683 if (!isPairInUse (PAIR_BC, ic))
685 return PAIR_BC;
687 else if (!IS_SM83 && !isPairInUse (PAIR_DE, ic))
689 return PAIR_DE;
691 else
693 return PAIR_INVALID;
697 static void
698 _tidyUp (char *buf)
700 /* Clean up the line so that it is 'prettier' */
701 /* If it is a label - can't do anything */
702 if (!strchr (buf, ':'))
704 /* Change the first (and probably only) ' ' to a tab so
705 everything lines up.
707 while (*buf)
709 if (*buf == ' ')
711 *buf = '\t';
712 break;
714 buf++;
719 static void
720 _vemit2 (const char *szFormat, va_list ap)
722 struct dbuf_s dbuf;
723 char *buffer, *p, *nextp;
725 dbuf_init (&dbuf, INITIAL_INLINEASM);
727 dbuf_tvprintf (&dbuf, szFormat, ap);
729 buffer = p = dbuf_detach_c_str (&dbuf);
731 _tidyUp (p);
733 /* Decompose multiline macros */
734 while ((nextp = strchr (p, '\n')))
736 *nextp = '\0';
737 emit_raw (p);
738 p = nextp + 1;
741 emit_raw (p);
743 dbuf_free (buffer);
746 static void
747 emitDebug (const char *szFormat, ...)
749 if (!DISABLE_DEBUG && !regalloc_dry_run && options.verboseAsm)
751 va_list ap;
753 va_start (ap, szFormat);
754 _vemit2 (szFormat, ap);
755 va_end (ap);
759 static void
760 emit2 (const char *szFormat, ...)
762 if (!regalloc_dry_run)
764 va_list ap;
766 va_start (ap, szFormat);
767 _vemit2 (szFormat, ap);
768 va_end (ap);
772 static PAIR_ID
773 getPartPairId (const asmop *aop, int offset)
775 if (aop->size <= offset + 1 || offset < 0)
776 return PAIR_INVALID;
778 if (aop->type != AOP_REG)
779 return PAIR_INVALID;
781 wassert (aop->aopu.aop_reg[offset] && aop->aopu.aop_reg[offset + 1]);
783 if ((aop->aopu.aop_reg[offset]->rIdx == C_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == B_IDX))
784 return PAIR_BC;
785 if ((aop->aopu.aop_reg[offset]->rIdx == E_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == D_IDX))
786 return PAIR_DE;
787 if ((aop->aopu.aop_reg[offset]->rIdx == L_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == H_IDX))
788 return PAIR_HL;
789 if ((aop->aopu.aop_reg[offset]->rIdx == IYL_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == IYH_IDX))
790 return PAIR_IY;
792 return PAIR_INVALID;
795 static PAIR_ID
796 getPairId_o (const asmop *aop, int offset)
798 if (offset >= 0 && offset + 2 <= aop->size)
800 if (aop->type == AOP_REG)
802 wassert (aop->aopu.aop_reg[offset] && aop->aopu.aop_reg[offset + 1]);
804 if ((aop->aopu.aop_reg[offset]->rIdx == C_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == B_IDX))
806 return PAIR_BC;
808 if ((aop->aopu.aop_reg[offset]->rIdx == E_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == D_IDX))
810 return PAIR_DE;
812 if ((aop->aopu.aop_reg[offset]->rIdx == L_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == H_IDX))
814 return PAIR_HL;
816 if ((aop->aopu.aop_reg[offset]->rIdx == IYL_IDX) && (aop->aopu.aop_reg[offset + 1]->rIdx == IYH_IDX))
818 return PAIR_IY;
822 return PAIR_INVALID;
825 static PAIR_ID
826 getPairId (const asmop *aop)
828 if (aop->size != 2)
829 return PAIR_INVALID;
830 return (getPairId_o (aop, 0));
834 /*-----------------------------------------------------------------*/
835 /* z80_emitDebuggerSymbol - associate the current code location */
836 /* with a debugger symbol */
837 /*-----------------------------------------------------------------*/
838 void
839 z80_emitDebuggerSymbol (const char *debugSym)
841 genLine.lineElement.isDebug = 1;
842 emit2 ("%s !equ !here", debugSym);
843 emit2 ("!global", debugSym);
844 genLine.lineElement.isDebug = 0;
847 // Todo: Handle IY correctly.
848 static unsigned char
849 ld_cost (const asmop *op1, int offset1, const asmop *op2, int offset2, bool count)
851 AOP_TYPE op1type = op1->type;
852 AOP_TYPE op2type = op2->type;
854 if (offset2 >= op2->size)
855 return (ld_cost (op1, offset1, ASMOP_ZERO, 0, count));
857 /* Costs are symmetric */
858 if (op1type != AOP_REG && (op2type == AOP_REG || op2type == AOP_DUMMY))
860 const asmop *tmp = op1;
861 op1 = op2;
862 op2 = tmp;
863 op1type = op1->type;
864 op2type = op2->type;
867 switch (op1type)
869 case AOP_REG:
870 case AOP_DUMMY:
871 switch (op2type)
873 case AOP_REG:
874 // ld r, r is dangerous, since support for it is inconsistent even among otherwise binary-compatible Rabbit devices.
875 if (IS_RAB && op1->aopu.aop_reg[offset1]->rIdx == op2->aopu.aop_reg[offset2]->rIdx)
876 werror (W_INTERNAL_ERROR, __FILE__, __LINE__, "ld r, r considered");
877 // eZ80 ld r, ir / ld ir, r / ld ir, ir
878 if (op1->aopu.aop_reg[offset1]->rIdx == IYL_IDX || op1->aopu.aop_reg[offset1]->rIdx == IYH_IDX ||
879 op2->aopu.aop_reg[offset2]->rIdx == IYL_IDX || op2->aopu.aop_reg[offset2]->rIdx == IYH_IDX)
881 if (count)
882 cost2 (2, 8, 0, 0, 0, 0, 2, 2);
883 return (2);
885 case AOP_DUMMY:
886 if (IS_TLCS90 && (op1->aopu.aop_reg[offset1]->rIdx == A_IDX || op1type == AOP_DUMMY))
888 if (count)
889 cost (1, 2);
890 return (1);
892 else
894 if (count)
895 cost2 (1 + IS_TLCS90, 4, 4, 2, 4, 4, 1, 1);
896 return (1 + IS_TLCS90);
898 case AOP_IMMD:
899 case AOP_LIT:
900 if (op1->aopu.aop_reg[offset1]->rIdx == IYL_IDX || op1->aopu.aop_reg[offset1]->rIdx == IYH_IDX)
902 if (count)
903 cost2 (3, 11, 0, 0, 0, 0, 2, 3); // ld ir, #n
904 return (3);
906 else
908 if (count)
909 cost2 (2, 7, 6, 4, 8, 4, 2, 2); // ld r, #n
910 return (2);
912 case AOP_SFR:
913 if (count)
915 cost2 (2, 11, 9, 0, 0, 0, 3, 3); // in a, (n)
916 if (!aopInReg (op1, 0, A_IDX) && op1type != AOP_DUMMY)
917 cost2 (1, 4, 4, 2, 4, 2, 1, 1); // ld r, a
919 return ((aopInReg (op1, 0, A_IDX) || op1type == AOP_DUMMY) ? 2 : 3);
920 case AOP_STK:
921 if (count)
922 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld r, d(ix)
923 return (3);
924 case AOP_HL:
925 if (count)
927 cost2 (3, 10, 9, 6, 12, 6, 3, 3); // ld hl, #nn
928 cost2 (1, 7, 6, 5, 8, 6, 2, 2); // ld r, (hl)
930 return (4);
931 case AOP_EXSTK: // Approximation. Don't really know if this is really exstk at this point, anyway.
932 case AOP_IY:
933 if (count)
935 cost2 (4, 14, 12, 8, 0, 6, 4, 4); // ld iy, #nn
936 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld r, d(iy)
938 return (7);
939 case AOP_PAIRPTR:
940 if (op2->aopu.aop_pairId == PAIR_HL)
942 if (count)
943 cost2 (1, 7, 6, 5, 8, 6, 2, 2); // ld r, (hl)
944 return (1);
946 if (op2->aopu.aop_pairId == PAIR_IY || op2->aopu.aop_pairId == PAIR_IX)
948 if (count)
949 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld r, d(ix)
950 return (3);
952 if (op2->aopu.aop_pairId == PAIR_BC || op2->aopu.aop_pairId == PAIR_DE)
954 if (count)
956 cost2 (1, 7, 6, 6, 8, 6, 2, 2); // ld a, (rr)
957 if (!aopInReg (op1, 0, A_IDX))
958 cost2 (1, 4, 4, 2, 4, 2, 1, 1); // ld r, a
960 return ((aopInReg (op1, 0, A_IDX) || op1type == AOP_DUMMY) ? 1 : 2);
962 default:
963 fprintf (stderr, "ld_cost op1: AOP_REG, op2: %d\n", (int) (op2type));
964 wassert (0);
966 case AOP_SFR:
967 if (count)
968 cost2 (2, 11, 10, 0, 0, 0, 3, 3); // out (n), a
969 if (aopInReg (op1, 0, A_IDX))
970 return (2);
971 else
972 return (2 + ld_cost (ASMOP_A, 0, op2, offset2, count));
973 case AOP_IY: /* 4 from ld iy, #... */
974 case AOP_EXSTK: /* 4 from ld iy, #... */
975 switch (op2type)
977 case AOP_IMMD:
978 case AOP_LIT:
979 return (8);
980 case AOP_SFR: /* 2 from in a, (...) */
981 return (9);
982 case AOP_STK:
983 case AOP_HL: /* 3 from ld hl, #... */
984 return (10);
985 case AOP_IY:
986 case AOP_EXSTK:
987 return (16);
988 default:
989 printf ("ld_cost op1: AOP_IY, op2: %d\n", (int) (op2type));
990 wassert (0);
992 case AOP_STK:
993 switch (op2type)
995 case AOP_IMMD:
996 case AOP_LIT:
997 if (count)
998 cost2 (4, 19, 15, 11, 0, 12, 5, 5); // ld d(ix), n
999 return (4);
1000 case AOP_SFR: /* 2 from in a, (...) */
1001 if (count)
1003 cost2 (2, 11, 9, 0, 0, 0, 3, 3); // in a, (n)
1004 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d(ix), a
1006 return (5);
1007 case AOP_STK:
1008 if (count)
1010 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld a, d(ix)
1011 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d(ix), a
1013 return (6);
1014 case AOP_HL:
1015 if (count)
1017 cost2 (3, 10, 9, 6, 12, 6, 3, 3); // ld hl, nn
1018 cost2 (1, 7, 6, 6, 8, 6, 2, 2); // ld a, (hl)
1019 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d(ix), a
1021 return (7);
1022 case AOP_EXSTK:
1023 case AOP_IY:
1024 if (count)
1026 cost2 (4, 14, 12, 8, 0, 6, 4, 4); // ld iy, #nn
1027 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld a, d(iy)
1028 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d(ix), a
1030 return (10);
1031 case AOP_PAIRPTR:
1032 if (count)
1033 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d(ix), a
1034 return (3 + ld_cost (ASMOP_A, 0, op2, offset2, count));
1035 default:
1036 printf ("ld_cost op1: AOP_STK, op2: %d\n", (int) (op2type));
1037 wassert (0);
1039 case AOP_HL:
1040 if (count)
1041 cost2 (3, 10, 9, 6, 12, 6, 3, 3); // ld hl, #nn
1042 switch (op2type)
1044 case AOP_REG:
1045 case AOP_DUMMY:
1046 if (count)
1047 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), r
1048 return (4);
1049 case AOP_IMMD:
1050 case AOP_LIT:
1051 if (count)
1052 cost2 (2 + IS_TLCS90, 10, 9, 7, 12, 8, 3, 3); // ld (hl), n
1053 return (5 + IS_TLCS90);
1054 case AOP_STK:
1055 if (count)
1057 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld a, d(ix)
1058 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), a
1060 return (7);
1061 case AOP_SFR:
1062 if (count)
1064 cost2 (2, 11, 9, 0, 0, 0, 3, 3); // in a, (n)
1065 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), a
1067 return (6);
1068 case AOP_HL:
1069 if (count)
1071 cost2 (3, 10, 9, 6, 12, 6, 3, 3); // ld hl, #nn
1072 cost2 (1, 7, 6, 5, 8, 6, 2, 2); // ld a, (hl)
1073 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), a
1075 return (8);
1076 case AOP_EXSTK:
1077 case AOP_IY:
1078 if (count)
1080 cost2 (4, 14, 12, 8, 0, 6, 4, 4); // ld iy, #nn
1081 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld a, d(iy)
1082 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), a
1084 return (11);
1085 default:
1086 printf ("ld_cost op1: AOP_HL, op2: %d", (int) (op2type));
1087 wassert (0);
1089 case AOP_LIT:
1090 case AOP_IMMD:
1091 wassertl (0, "Trying to assign a value to a literal");
1092 break;
1093 case AOP_PAIRPTR:
1094 switch (op2type)
1096 case AOP_REG:
1097 if (op1->aopu.aop_pairId == PAIR_HL)
1099 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
1100 return (1);
1102 else if (op1->aopu.aop_pairId == PAIR_IY || op1->aopu.aop_pairId == PAIR_IX)
1104 cost2 (3, 19, 15, 9, 0, 10, 4, 5);
1105 return (3);
1107 else
1108 wassert (0);
1109 break;
1110 case AOP_LIT:
1111 if (op1->aopu.aop_pairId == PAIR_HL)
1113 cost2 (2, 10, 9, 7, 12, 8, 3, 3);
1114 return (2);
1116 else if (op1->aopu.aop_pairId == PAIR_IY || op1->aopu.aop_pairId == PAIR_IX)
1118 cost2 (4, 19, 15, 11, 0, 12, 5, 5);
1119 return (4);
1121 else
1122 wassert (0);
1123 break;
1124 default:
1125 wassert (0);
1127 break;
1128 default:
1129 printf ("ld_cost op1: %d\n", (int) (op1type));
1130 wassert (0);
1132 return (12); // Fallback
1135 static void
1136 op8_cost (const asmop *op, int offset)
1138 switch (op->type)
1140 case AOP_REG:
1141 if (op->aopu.aop_reg[offset]->rIdx == IYL_IDX || op->aopu.aop_reg[offset]->rIdx == IYH_IDX) // eZ80
1143 wassert (HAS_IYL_INST);
1144 cost (2, 2);
1145 return;
1147 case AOP_DUMMY:
1148 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
1149 return;
1150 case AOP_IMMD:
1151 case AOP_LIT:
1152 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
1153 return;
1154 case AOP_STK:
1155 if (!IS_SM83)
1157 cost2 (3, 19, 15, 9, 0, 10, 4, 5);
1158 return;
1160 cost (1, 8); // add hl, sp
1161 case AOP_HL:
1162 cost2 (3 + 1, 10 + 7, 9 + 6, 6 + 5, 12 + 8, 6 + 6, 3 + 2, 3 + 2);
1163 return;
1164 case AOP_IY: /* 4 from ld iy, #... */
1165 case AOP_EXSTK: /* 4 from ld iy, #... */
1166 cost2 (4 + 3, 12 + 19, 12 + 15, 8 + 9, 0 + 0, 6 + 10, 4 + 4, 4 + 5);
1167 return;
1168 case AOP_PAIRPTR:
1169 if (op->aopu.aop_pairId == PAIR_HL)
1170 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
1171 else if (op->aopu.aop_pairId == PAIR_IY || op->aopu.aop_pairId == PAIR_IX)
1172 cost2 (3, 19, 15, 9, 0, 10, 4, 5);
1173 else
1174 wassert (0);
1175 return;
1176 default:
1177 printf ("op8_cost op: %d\n", (int) (op->type));
1178 wassert (0);
1182 static void
1183 incdec_cost (const asmop *op, int offset)
1185 switch (op->type)
1187 case AOP_REG:
1188 if (op->aopu.aop_reg[offset]->rIdx == IYL_IDX || op->aopu.aop_reg[offset]->rIdx == IYH_IDX) // eZ80, r800
1190 wassert (HAS_IYL_INST);
1191 cost (2, 2);
1192 return;
1194 case AOP_DUMMY:
1195 cost2 (1, 4, 4, 2, 4, 2, 2, 1);
1196 return;
1197 case AOP_STK:
1198 if (!IS_SM83)
1200 cost2 (3, 23, 18, 12, 0, 12, 6, 7);
1201 return;
1203 cost (1, 8); // add hl, sp
1204 case AOP_HL:
1205 cost2 (3 + 1, 10 + 11, 9 + 10, 6 + 8, 12 + 12, 6 + 8, 3 + 5, 3 + 4);
1206 return;
1207 case AOP_IY: /* 4 from ld iy, #... */
1208 case AOP_EXSTK: /* 4 from ld iy, #... */
1209 cost2 (4 + 3, 14 + 23, 12 + 18, 8 + 12, 0 + 0, 6 + 12, 4 + 6, 4 + 7);
1210 return;
1211 case AOP_PAIRPTR:
1212 if (op->aopu.aop_pairId == PAIR_HL)
1214 cost2 (1, 11, 10, 8, 12, 8, 5, 4);
1215 return;
1217 if (op->aopu.aop_pairId == PAIR_IY || op->aopu.aop_pairId == PAIR_IX)
1219 cost2 (3, 23, 18, 12, 0, 12, 6, 7);
1220 return;
1222 default:
1223 printf ("op8_cost op: %d\n", (int) (op->type));
1224 wassert (0);
1228 static void
1229 bit8_cost (const asmop *op)
1231 switch (op->type)
1233 case AOP_REG:
1234 case AOP_DUMMY:
1235 cost2 (2, 8, 7, 4, 8, 4, 2, 2);
1236 return;
1237 case AOP_STK:
1238 if (!IS_SM83)
1240 cost2 (4, 23, 19, 13, 0, 12, 7, 7);
1241 return;
1243 cost (1, 8); // add hl, sp
1244 case AOP_HL: /* 3 from ld hl, #... */
1245 cost2 (3 + 2, 10 + 15, 9 + 13, 6 + 10, 12 + 16, 6 + 8, 3 + 5, 3 + 5);
1246 return;
1247 case AOP_IY: /* 4 from ld iy, #... */
1248 case AOP_EXSTK: /* 4 from ld iy, #... */
1249 cost2 (4 + 4, 14 + 23, 12 + 19, 8 + 13, 0 + 0, 6 + 12, 4 + 7, 4 + 7);
1250 return;
1251 default:
1252 printf ("bit8_cost op: %d\n", (int) (op->type));
1253 wassert (0);
1257 static void
1258 emit3Cost (enum asminst inst, const asmop *op1, int offset1, const asmop *op2, int offset2)
1260 if (op2 && offset2 >= op2->size)
1261 op2 = ASMOP_ZERO;
1263 switch (inst)
1265 case A_CPL:
1266 case A_RLA:
1267 case A_RLCA:
1268 case A_RRA:
1269 case A_RRCA:
1270 cost2 (1, 4, 3, 2, 4, 2, 1, 1);
1271 return;
1272 case A_NEG:
1273 cost2 (2, 8, 6, 4, 0, 2, 2, 2);
1274 return;
1275 case A_RLD:
1276 case A_RRD:
1277 cost2 (2, 18, 16, 0, 0, 12, 5, 5);
1278 return;
1279 case A_LD:
1280 ld_cost (op1, offset1, op2, offset2, true);
1281 return;
1282 case A_ADD:
1283 case A_ADC:
1284 case A_AND:
1285 case A_CP:
1286 case A_OR:
1287 case A_SBC:
1288 case A_SUB:
1289 case A_XOR:
1290 op8_cost (op2, offset2);
1291 return;
1292 case A_DEC:
1293 case A_INC:
1294 incdec_cost (op1, offset1);
1295 return;
1296 case A_RL:
1297 case A_RLC:
1298 case A_RR:
1299 case A_RRC:
1300 case A_SLA:
1301 case A_SRA:
1302 case A_SRL:
1303 case A_SWAP:
1304 bit8_cost (op1);
1305 return;
1306 default:
1307 wassertl (0, "Tried get cost for unknown instruction");
1311 static void
1312 emit3wCost (enum asminst inst, const asmop *op1, int offset1, const asmop *op2, int offset2)
1314 if (op2 && offset2 >= op2->size)
1315 op2 = ASMOP_ZERO;
1317 switch (inst)
1319 case A_INC:
1320 case A_DEC:
1321 if (aopInReg (op1, offset1, IY_IDX))
1322 cost2 (2 - IS_TLCS90, 10, 7, 4, 0, 4, 2, 2);
1323 else
1324 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
1325 return;
1326 case A_ADD:
1327 if (aopInReg (op1, offset1, IY_IDX))
1328 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
1329 else
1330 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
1331 return;
1332 case A_ADC:
1333 case A_SBC:
1334 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
1335 return;
1336 case A_EX:
1337 cost2 (1, 4, 3, 2, 0, 2, 1, 1);
1338 return;
1339 default:
1340 wassertl (0, "Tried get cost for unknown instruction");
1344 static void
1345 emit3_o (enum asminst inst, asmop *op1, int offset1, asmop *op2, int offset2)
1347 unsigned long cost, bytecost;
1348 float statecost;
1350 emit3Cost (inst, op1, offset1, op2, offset2);
1352 if (regalloc_dry_run)
1353 return;
1355 cost = regalloc_dry_run_cost;
1356 bytecost = regalloc_dry_run_cost_bytes;
1357 statecost = regalloc_dry_run_cost_states;
1358 if (!op1)
1359 emit2 ("%s", asminstnames[inst]);
1360 else if (!op2)
1361 emit2 ("%s %s", asminstnames[inst], aopGet (op1, offset1, FALSE));
1362 else
1364 char *l = Safe_strdup (aopGet (op1, offset1, FALSE));
1365 emit2 ("%s %s, %s", asminstnames[inst], l, aopGet (op2, offset2, FALSE));
1366 Safe_free (l);
1369 regalloc_dry_run_cost = cost;
1370 regalloc_dry_run_cost_bytes = bytecost;
1371 regalloc_dry_run_cost_states = statecost;
1372 //emitDebug(";emit3_o cost: %d total so far: %d", (int)emit3Cost(inst, op1, offset1, op2, offset2), (int)cost);
1375 static void
1376 emit3w_o (enum asminst inst, asmop *op1, int offset1, asmop *op2, int offset2)
1378 unsigned int cost, bytecost;
1379 float statecost;
1381 emit3wCost (inst, op1, offset1, op2, offset2);
1383 if (regalloc_dry_run)
1384 return;
1386 cost = regalloc_dry_run_cost;
1387 bytecost = regalloc_dry_run_cost_bytes;
1388 statecost = regalloc_dry_run_cost_states;
1389 if (!op1)
1390 emit2 ("%s", asminstnames[inst]);
1391 else if (!op2)
1392 emit2 ("%s %s", asminstnames[inst], aopGet (op1, offset1, true));
1393 else
1395 char *l = Safe_strdup (aopGet (op1, offset1, true));
1396 emit2 ("%s %s, %s", asminstnames[inst], l, aopGet (op2, offset2, true));
1397 Safe_free (l);
1400 regalloc_dry_run_cost = cost;
1401 regalloc_dry_run_cost_bytes = bytecost;
1402 regalloc_dry_run_cost_states = statecost;
1403 //emitDebug(";emit3_o cost: %d total so far: %d", (int)emit3Cost(inst, op1, offset1, op2, offset2), (int)cost);
1406 static void
1407 emit3 (enum asminst inst, asmop *op1, asmop *op2)
1409 emit3_o (inst, op1, 0, op2, 0);
1412 static void
1413 emit3w (enum asminst inst, asmop *op1, asmop *op2)
1415 emit3w_o (inst, op1, 0, op2, 0);
1418 static void
1419 _emitMove (const char *to, const char *from)
1421 if (STRCASECMP (to, from) != 0)
1423 emit2 ("ld %s, %s", to, from);
1425 else
1427 // Optimise it out.
1428 // Could leave this to the peephole, but sometimes the peephole is inhibited.
1432 static void
1433 _emitMove3 (asmop *to, int to_offset, asmop *from, int from_offset)
1435 /* Todo: Longer list of moves that can be optimized out. */
1436 if (to_offset == from_offset)
1438 if (to->type == AOP_REG && from->type == AOP_REG && to->aopu.aop_reg[to_offset] == from->aopu.aop_reg[from_offset])
1439 return;
1442 emit3_o (A_LD, to, to_offset, from, from_offset);
1445 #if 0
1446 static const char *aopNames[] =
1448 "AOP_INVALID",
1449 "AOP_LIT",
1450 "AOP_REG",
1451 "AOP_DIR",
1452 "AOP_SFR",
1453 "AOP_STK",
1454 "AOP_IMMD",
1455 "AOP_CRY",
1456 "AOP_IY",
1457 "AOP_HL",
1458 "AOP_EXSTK",
1459 "AOP_PAIRPT",
1460 "AOP_DUMMY"
1463 static void
1464 aopDump (const char *plabel, asmop * aop)
1466 int i;
1467 char regbuf[9];
1468 char *rbp = regbuf;
1470 emitDebug ("; Dump of %s: type %s size %u", plabel, aopNames[aop->type], aop->size);
1471 switch (aop->type)
1473 case AOP_EXSTK:
1474 case AOP_STK:
1475 emitDebug ("; aop_stk %d", aop->aopu.aop_stk);
1476 break;
1477 case AOP_REG:
1478 for (i = aop->size - 1; i >= 0; i--)
1479 *rbp++ = *(aop->aopu.aop_reg[i]->name);
1480 *rbp = '\0';
1481 emitDebug ("; reg = %s", regbuf);
1482 break;
1483 case AOP_PAIRPTR:
1484 emitDebug ("; pairptr = (%s)", _pairs[aop->aopu.aop_pairId].name);
1486 default:
1487 /* No information. */
1488 break;
1491 #endif
1493 static void
1494 _moveA (const char *moveFrom)
1496 _emitMove ("a", moveFrom);
1499 /* Load aop into A */
1500 static void
1501 _moveA3 (asmop * from, int offset)
1503 _emitMove3 (ASMOP_A, 0, from, offset);
1506 static const char *
1507 getPairName (asmop *aop)
1509 if (aop->type == AOP_REG)
1511 switch (aop->aopu.aop_reg[0]->rIdx)
1513 case C_IDX:
1514 return "bc";
1515 break;
1516 case E_IDX:
1517 return "de";
1518 break;
1519 case L_IDX:
1520 return "hl";
1521 break;
1522 case IYL_IDX:
1523 return "iy";
1524 break;
1527 wassertl (0, "Tried to get the pair name of something that isn't a pair");
1528 return NULL;
1531 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
1532 static bool
1533 isPair (const asmop *aop)
1535 return (getPairId (aop) != PAIR_INVALID);
1538 /** Returns TRUE if the registers used in aop cannot be split into high
1539 and low halves */
1540 static bool
1541 isUnsplitable (const asmop * aop)
1543 switch (getPairId (aop))
1545 case PAIR_IX:
1546 case PAIR_IY:
1547 return TRUE;
1548 default:
1549 return FALSE;
1551 return FALSE;
1554 static void
1555 spillPair (PAIR_ID pairId)
1557 _G.pairs[pairId].last_type = AOP_INVALID;
1558 _G.pairs[pairId].base = NULL;
1561 /* Given a register name, spill the pair (if any) the register is part of */
1562 static void
1563 spillPairReg (const char *regname)
1565 if (strlen (regname) == 1)
1567 switch (*regname)
1569 case 'h':
1570 case 'l':
1571 spillPair (PAIR_HL);
1572 break;
1573 case 'd':
1574 case 'e':
1575 spillPair (PAIR_DE);
1576 break;
1577 case 'b':
1578 case 'c':
1579 spillPair (PAIR_BC);
1580 break;
1585 /* swap pairs fiels type/base */
1586 static void
1587 swapPairs (PAIR_ID pair1Id, PAIR_ID pair2Id)
1589 /*AOP_TYPE tt = _G.pairs[pair1Id].last_type;
1590 _G.pairs[pair1Id].last_type = _G.pairs[pair2Id].last_type;
1591 _G.pairs[pair2Id].last_type = tt;
1592 const char *tb = _G.pairs[pair1Id].base;
1593 unsigned int tv = _G.pairs[pair1Id].value;
1594 _G.pairs[pair1Id].base = _G.pairs[pair2Id].base;
1595 _G.pairs[pair2Id].base = tb;
1596 _G.pairs[pair1Id].value = _G.pairs[pair2Id].value;
1597 _G.pairs[pair2Id].value = tv;*/
1599 // For now just spill both: Making this work would require proper tracking of de (i.e. adding spillPair (PAIR_DE) as consistently as has been done for spillPair (PAIR_HL)
1600 spillPair (pair1Id);
1601 spillPair (pair2Id);
1604 static void
1605 _push (PAIR_ID pairId)
1607 emit2 ("push %s", _pairs[pairId].name);
1608 if (pairId == PAIR_IX || pairId == PAIR_IY)
1609 cost2 (2 - IS_TLCS90, 15, 14, 12, 16, 8, 4, 5);
1610 else
1611 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
1612 _G.stack.pushed += 2;
1615 static void
1616 _pop (PAIR_ID pairId)
1618 if (pairId != PAIR_INVALID)
1620 emit2 ("pop %s", _pairs[pairId].name);
1621 if (pairId == PAIR_IX || pairId == PAIR_IY)
1622 cost2 (2 - IS_TLCS90, 14, 12, 9, 12, 10, 4, 4);
1623 else
1624 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
1625 _G.stack.pushed -= 2;
1626 spillPair (pairId);
1630 static void
1631 genMovePairPair (PAIR_ID srcPair, PAIR_ID dstPair)
1633 switch (dstPair)
1635 case PAIR_IX:
1636 case PAIR_IY:
1637 case PAIR_AF:
1638 _push (srcPair);
1639 _pop (dstPair);
1640 break;
1641 case PAIR_BC:
1642 case PAIR_DE:
1643 case PAIR_HL:
1644 if (srcPair == PAIR_IX || srcPair == PAIR_IY)
1646 _push (srcPair);
1647 _pop (dstPair);
1649 else
1651 emit2 ("ld %s, %s", _pairs[dstPair].l, _pairs[srcPair].l);
1652 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
1653 emit2 ("ld %s, %s", _pairs[dstPair].h, _pairs[srcPair].h);
1654 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
1656 break;
1657 default:
1658 wassertl (0, "Tried to move a nonphysical pair");
1660 _G.pairs[dstPair].last_type = _G.pairs[srcPair].last_type;
1661 _G.pairs[dstPair].base = _G.pairs[srcPair].base;
1662 _G.pairs[dstPair].value = _G.pairs[srcPair].value;
1663 _G.pairs[dstPair].offset = _G.pairs[srcPair].offset;
1667 /*-----------------------------------------------------------------*/
1668 /* newAsmop - creates a new asmOp */
1669 /*-----------------------------------------------------------------*/
1670 static asmop *
1671 newAsmop (short type)
1673 asmop *aop;
1675 aop = traceAlloc (&_G.trace.aops, Safe_alloc (sizeof (asmop)));
1676 aop->type = type;
1677 memset (aop->regs, -1, 9);
1678 aop->valinfo.anything = true;
1679 return aop;
1682 /*-----------------------------------------------------------------*/
1683 /* aopForSym - for a true symbol */
1684 /*-----------------------------------------------------------------*/
1685 static asmop *
1686 aopForSym (const iCode * ic, symbol * sym, bool requires_a)
1688 asmop *aop;
1689 memmap *space;
1691 wassert (ic);
1692 wassert (sym);
1693 wassert (sym->etype);
1695 space = SPEC_OCLS (sym->etype);
1697 /* if already has one */
1698 if (sym->aop)
1699 return sym->aop;
1701 /* Assign depending on the storage class */
1702 if (sym->onStack || sym->iaccess)
1704 /* The pointer that is used depends on how big the offset is.
1705 Normally everything is AOP_STK, but for offsets of < -128 or
1706 > 127 on the Z80 an extended stack pointer is used.
1708 if (!IS_SM83 && (_G.omitFramePtr || sym->stack < INT8MIN || sym->stack > (int) (INT8MAX - getSize (sym->type))))
1710 emitDebug ("; AOP_EXSTK for %s, _G.omitFramePtr %d, sym->stack %d, size %d", sym->rname, (int) (_G.omitFramePtr),
1711 sym->stack, getSize (sym->type));
1712 sym->aop = aop = newAsmop (AOP_EXSTK);
1714 else
1716 emitDebug ("; AOP_STK for %s", sym->rname);
1717 sym->aop = aop = newAsmop (AOP_STK);
1720 memset (aop->regs, -1, sizeof(aop->regs));
1721 aop->size = getSize (sym->type);
1722 aop->aopu.aop_stk = sym->stack;
1723 return aop;
1726 /* special case for a function */
1727 if (IS_FUNC (sym->type))
1729 sym->aop = aop = newAsmop (AOP_IMMD);
1730 aop->aopu.aop_immd = traceAlloc (&_G.trace.aops, Safe_strdup (sym->rname));
1731 aop->size = 2;
1732 return aop;
1735 if (IN_REGSP (space))
1737 /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
1738 if (IS_SM83)
1740 /* if it is in direct space */
1741 if (!requires_a)
1743 sym->aop = aop = newAsmop (AOP_SFR);
1744 aop->aopu.aop_dir = sym->rname;
1745 aop->size = getSize (sym->type);
1746 /* emitDebug ("; AOP_SFR for %s", sym->rname); */
1747 return aop;
1750 else
1752 /*.p.t.20030716 adding SFR support to the Z80 port */
1753 aop = newAsmop (AOP_SFR);
1754 sym->aop = aop;
1755 aop->aopu.aop_dir = sym->rname;
1756 aop->size = getSize (sym->type);
1757 aop->paged = FUNC_REGBANK (sym->type);
1758 aop->bcInUse = isPairInUse (PAIR_BC, ic);
1759 /* emitDebug (";Z80 AOP_SFR for %s banked:%d bc:%d", sym->rname, FUNC_REGBANK (sym->type), aop->bcInUse); */
1761 return (aop);
1765 /* only remaining is far space */
1766 /* in which case DPTR gets the address */
1767 if (IS_SM83 || IY_RESERVED)
1769 /* emitDebug ("; AOP_HL for %s", sym->rname); */
1770 sym->aop = aop = newAsmop (AOP_HL);
1772 else
1773 sym->aop = aop = newAsmop (AOP_IY);
1775 aop->size = getSize (sym->type);
1776 aop->aopu.aop_dir = sym->rname;
1778 /* if it is in code space */
1779 if (IN_CODESPACE (space))
1780 aop->code = 1;
1782 return aop;
1785 /*-----------------------------------------------------------------*/
1786 /* aopForRemat - rematerializes an object */
1787 /*-----------------------------------------------------------------*/
1788 static asmop *
1789 aopForRemat (symbol *sym)
1791 iCode *ic = sym->rematiCode;
1792 int val = 0;
1793 asmop *aop;
1794 struct dbuf_s dbuf;
1796 wassert(ic);
1798 for (;;)
1800 if (ic->op == '+')
1802 if (isOperandLiteral (IC_RIGHT (ic)))
1804 val += (int) operandLitValue (IC_RIGHT (ic));
1805 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
1807 else
1809 val += (int) operandLitValue (IC_LEFT (ic));
1810 ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
1813 else if (ic->op == '-')
1815 val -= (int) operandLitValue (IC_RIGHT (ic));
1816 ic = OP_SYMBOL (IC_LEFT (ic))->rematiCode;
1818 else if (IS_CAST_ICODE (ic))
1820 ic = OP_SYMBOL (IC_RIGHT (ic))->rematiCode;
1822 else if (ic->op == ADDRESS_OF)
1824 val += (int) operandLitValue (IC_RIGHT (ic));
1825 break;
1827 else
1828 break;
1831 if (OP_SYMBOL (IC_LEFT (ic))->onStack)
1833 aop = newAsmop (AOP_STL);
1834 aop->aopu.aop_stk = (long)(OP_SYMBOL (IC_LEFT (ic))->stack) + val;
1836 else
1838 aop = newAsmop (AOP_IMMD);
1840 dbuf_init (&dbuf, 128);
1841 if (val)
1843 dbuf_tprintf (&dbuf, "(%s %c %d)", OP_SYMBOL (IC_LEFT (ic))->rname, val >= 0 ? '+' : '-', abs (val) & 0xffff);
1845 else
1847 dbuf_append_str (&dbuf, OP_SYMBOL (IC_LEFT (ic))->rname);
1849 aop->aopu.aop_immd = traceAlloc (&_G.trace.aops, dbuf_detach_c_str (&dbuf));
1852 return aop;
1855 #if 0 // No longer used?
1856 /*-----------------------------------------------------------------*/
1857 /* regsInCommon - two operands have some registers in common */
1858 /*-----------------------------------------------------------------*/
1859 static bool
1860 regsInCommon (operand * op1, operand * op2)
1862 symbol *sym1, *sym2;
1863 int i;
1865 /* if they have registers in common */
1866 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1867 return FALSE;
1869 sym1 = OP_SYMBOL (op1);
1870 sym2 = OP_SYMBOL (op2);
1872 if (sym1->nRegs == 0 || sym2->nRegs == 0)
1873 return FALSE;
1875 for (i = 0; i < sym1->nRegs; i++)
1877 int j;
1878 if (!sym1->regs[i])
1879 continue;
1881 for (j = 0; j < sym2->nRegs; j++)
1883 if (!sym2->regs[j])
1884 continue;
1886 if (sym2->regs[j] == sym1->regs[i])
1887 return TRUE;
1891 return FALSE;
1893 #endif
1895 /*-----------------------------------------------------------------*/
1896 /* operandsEqu - equivalent */
1897 /*-----------------------------------------------------------------*/
1898 static bool
1899 operandsEqu (operand * op1, operand * op2)
1901 symbol *sym1, *sym2;
1903 /* if they not symbols */
1904 if (!IS_SYMOP (op1) || !IS_SYMOP (op2))
1905 return FALSE;
1907 sym1 = OP_SYMBOL (op1);
1908 sym2 = OP_SYMBOL (op2);
1910 /* if both are itemps & one is spilt
1911 and the other is not then false */
1912 if (IS_ITEMP (op1) && IS_ITEMP (op2) && sym1->isspilt != sym2->isspilt)
1913 return FALSE;
1915 /* if they are the same */
1916 if (sym1 == sym2)
1917 return 1;
1919 if (sym1->rname[0] && sym2->rname[0] && strcmp (sym1->rname, sym2->rname) == 0)
1920 return 2;
1922 /* if left is a tmp & right is not */
1923 if (IS_ITEMP (op1) && !IS_ITEMP (op2) && sym1->isspilt && (sym1->usl.spillLoc == sym2))
1924 return 3;
1926 if (IS_ITEMP (op2) && !IS_ITEMP (op1) && sym2->isspilt && sym1->level > 0 && (sym2->usl.spillLoc == sym1))
1927 return 4;
1929 return FALSE;
1932 /*-----------------------------------------------------------------*/
1933 /* sameRegs - two asmops have the same registers */
1934 /*-----------------------------------------------------------------*/
1935 static bool
1936 sameRegs (const asmop *aop1, const asmop *aop2)
1938 int i;
1940 if (aop1->type == AOP_SFR || aop2->type == AOP_SFR)
1941 return FALSE;
1943 if (aop1 == aop2)
1944 return TRUE;
1946 if (!regalloc_dry_run && // Todo: Check if always enabling this even for dry runs tends to result in better code.
1947 (aop1->type == AOP_STK && aop2->type == AOP_STK ||
1948 aop1->type == AOP_EXSTK && aop2->type == AOP_EXSTK))
1949 return (aop1->aopu.aop_stk == aop2->aopu.aop_stk);
1951 if (aop1->type != AOP_REG || aop2->type != AOP_REG)
1952 return FALSE;
1954 if (aop1->size != aop2->size)
1955 return FALSE;
1957 for (i = 0; i < aop1->size; i++)
1958 if (aop1->aopu.aop_reg[i] != aop2->aopu.aop_reg[i])
1959 return FALSE;
1961 return TRUE;
1964 /*-----------------------------------------------------------------*/
1965 /* aopSame - two asmops refer to the same storage */
1966 /*-----------------------------------------------------------------*/
1967 static bool
1968 aopSame (const asmop *aop1, int offset1, const asmop *aop2, int offset2, int size)
1970 if (aop1 == aop2 && offset1 == offset2)
1971 return (true);
1973 for(; size; size--, offset1++, offset2++)
1975 if (offset1 >= aop1->size || offset2 >= aop2->size)
1976 return (false);
1978 if (aop1->type == AOP_REG && aop2->type == AOP_REG && // Same register
1979 aop1->aopu.aop_reg[offset1]->rIdx == aop2->aopu.aop_reg[offset2]->rIdx)
1980 continue;
1982 if (aopOnStack (aop1, offset1, 1) && aopOnStack (aop2, offset2, 1) && !regalloc_dry_run && // Same stack location - stack locations might change after register allocation, so make no assumption during dry run.
1983 aop1->aopu.aop_stk + offset1 == aop2->aopu.aop_stk + offset2)
1984 continue;
1986 if (aop1->type == AOP_LIT && aop2->type == AOP_LIT && // Same literal
1987 byteOfVal (aop1->aopu.aop_lit, offset1) == byteOfVal (aop2->aopu.aop_lit, offset2))
1988 continue;
1990 // Same file-scope variable.
1991 if ((aop1->type == AOP_DIR || aop1->type == AOP_HL || aop1->type == AOP_IY) &&
1992 (aop2->type == AOP_DIR || aop2->type == AOP_HL || aop2->type == AOP_IY) &&
1993 offset1 == offset2 && !strcmp(aop1->aopu.aop_dir, aop2->aopu.aop_dir))
1994 return (true);
1996 return (false);
1999 return (true);
2002 /*-----------------------------------------------------------------*/
2003 /* aopOp - allocates an asmop for an operand : */
2004 /*-----------------------------------------------------------------*/
2005 static void
2006 aopOp (operand *op, const iCode *ic, bool result, bool requires_a)
2008 asmop *aop;
2009 symbol *sym;
2010 int i;
2012 if (!op)
2013 return;
2015 /* if this a literal */
2016 if (IS_OP_LITERAL (op)) /* TODO: && !op->isaddr, handle address literals in a sane way */
2018 op->aop = aop = newAsmop (AOP_LIT);
2019 aop->aopu.aop_lit = OP_VALUE (op);
2020 aop->size = getSize (operandType (op));
2021 if (!result)
2022 op->aop->valinfo = getOperandValinfo (ic, op);
2023 else if(ic->resultvalinfo)
2024 op->aop->valinfo = *ic->resultvalinfo;
2025 return;
2028 /* if already has a asmop then continue */
2029 if (op->aop)
2031 if (op->aop->type == AOP_SFR)
2033 op->aop->bcInUse = isPairInUse (PAIR_BC, ic);
2035 return;
2038 /* if the underlying symbol has a aop */
2039 if (IS_SYMOP (op) && OP_SYMBOL (op)->aop)
2041 op->aop = OP_SYMBOL (op)->aop;
2042 if (op->aop->type == AOP_SFR)
2044 op->aop->bcInUse = isPairInUse (PAIR_BC, ic);
2046 if (result && ic->resultvalinfo)
2047 valinfo_union (&(op->aop->valinfo), *ic->resultvalinfo);
2048 else if (result)
2049 op->aop->valinfo.anything = true;
2050 return;
2053 /* if this is a true symbol */
2054 if (IS_TRUE_SYMOP (op))
2056 op->aop = aopForSym (ic, OP_SYMBOL (op), requires_a);
2057 if (!result)
2058 op->aop->valinfo = getOperandValinfo (ic, op);
2059 else if(ic->resultvalinfo)
2060 op->aop->valinfo = *ic->resultvalinfo;
2061 return;
2064 /* this is a temporary : this has
2065 only four choices :
2066 a) register
2067 b) spillocation
2068 c) rematerialize
2069 d) conditional
2070 e) can be a return use only */
2072 sym = OP_SYMBOL (op);
2074 /* if the type is a conditional */
2075 if (sym->regType == REG_CND)
2077 aop = op->aop = sym->aop = newAsmop (AOP_CRY);
2078 aop->size = 0;
2079 return;
2082 /* if it is spilt then two situations
2083 a) is rematerialize
2084 b) has a spill location */
2085 if (sym->isspilt || sym->nRegs == 0)
2087 wassert (!sym->ruonly); // iTemp optimized out via ifxForOp shouldn'T reach here.
2089 wassert (!sym->accuse); // Should not happen anymore with curetn register allocator.
2091 /* rematerialize it NOW */
2092 if (sym->remat)
2094 sym->aop = op->aop = aop = aopForRemat (sym);
2095 aop->size = getSize (sym->type);
2096 if (!result)
2097 aop->valinfo = getOperandValinfo (ic, op);
2098 else if(ic->resultvalinfo)
2099 aop->valinfo = *ic->resultvalinfo;
2100 return;
2103 /* On-stack for dry run. */
2104 if (sym->nRegs && regalloc_dry_run)
2106 sym->aop = op->aop = aop = newAsmop (_G.omitFramePtr ? AOP_EXSTK : AOP_STK);
2107 aop->size = getSize (sym->type);
2108 if (!result)
2109 aop->valinfo = getOperandValinfo (ic, op);
2110 else if(ic->resultvalinfo)
2111 aop->valinfo = *ic->resultvalinfo;
2112 return;
2115 /* On stack. */
2116 if (sym->isspilt && sym->usl.spillLoc)
2118 asmop *oldAsmOp = NULL;
2120 if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
2122 /* force a new aop if sizes differ */
2123 oldAsmOp = sym->usl.spillLoc->aop;
2124 sym->usl.spillLoc->aop = NULL;
2126 sym->aop = op->aop = aop = aopForSym (ic, sym->usl.spillLoc, requires_a);
2127 if (getSize (sym->type) != getSize (sym->usl.spillLoc->type))
2129 /* Don't reuse the new aop, go with the last one */
2130 sym->usl.spillLoc->aop = oldAsmOp;
2132 aop->size = getSize (sym->type);
2133 if (!result)
2134 aop->valinfo = getOperandValinfo (ic, op);
2135 else if(ic->resultvalinfo)
2136 aop->valinfo = *ic->resultvalinfo;
2137 return;
2140 /* else must be a dummy iTemp */
2141 sym->aop = op->aop = aop = newAsmop (AOP_DUMMY);
2142 aop->size = getSize (sym->type);
2143 if (!result)
2144 aop->valinfo = getOperandValinfo (ic, op);
2145 else if(ic->resultvalinfo)
2146 aop->valinfo = *ic->resultvalinfo;
2147 return;
2150 /* must be in a register */
2151 sym->aop = op->aop = aop = newAsmop (AOP_REG);
2152 aop->size = sym->nRegs;
2153 if (!result)
2154 aop->valinfo = getOperandValinfo (ic, op);
2155 else if(ic->resultvalinfo)
2156 aop->valinfo = *ic->resultvalinfo;
2157 memset (aop->regs, -1, sizeof(aop->regs));
2158 for (i = 0; i < sym->nRegs; i++)
2160 wassertl (sym->regs[i], "Symbol in register, but no register assigned.");
2161 if(!sym->regs[i])
2162 fprintf(stderr, "Symbol %s at ic %d.\n", sym->name, ic->key);
2163 aop->aopu.aop_reg[i] = sym->regs[i];
2164 aop->regs[sym->regs[i]->rIdx] = i;
2168 // Get asmop for registers containing the return type of function
2169 // Returns 0 if the function does not have a return value or it is not returned in registers.
2170 static asmop *
2171 aopRet (sym_link *ftype)
2173 wassert (IS_FUNC (ftype));
2175 // Adjust returnregs in isReturned in peep.c accordingly when changing asmop_return here.
2177 int size = getSize (ftype->next);
2179 const bool bigreturn = (size > 4) || IS_STRUCT (ftype->next);
2180 if (bigreturn)
2181 return (0);
2183 if (FUNC_SDCCCALL (ftype) == 0 || FUNC_ISSMALLC (ftype) || FUNC_ISZ88DK_FASTCALL (ftype))
2184 switch (size)
2186 case 1:
2187 return (IS_SM83 ? ASMOP_E : ASMOP_L);
2188 case 2:
2189 return (IS_SM83 ? ASMOP_DE : ASMOP_HL);
2190 case 3:
2191 case 4:
2192 return (IS_SM83 ? ASMOP_HLDE : ASMOP_DEHL);
2193 default:
2194 return 0;
2197 wassert (FUNC_SDCCCALL (ftype) == 1);
2199 switch (size)
2201 case 1:
2202 return (ASMOP_A);
2203 case 2:
2204 if (IS_RAB || IS_TLCS90 || IS_EZ80_Z80)
2205 return ASMOP_HL;
2206 else if (IS_SM83)
2207 return ASMOP_BC;
2208 else
2209 return ASMOP_DE;
2210 case 3:
2211 case 4:
2212 return (IS_SM83 ? ASMOP_DEBC : ASMOP_HLDE);
2213 default:
2214 return 0;
2218 // Get asmop for registers containing a parameter
2219 // Returns 0 if the parameter is passed on the stack
2220 static asmop *
2221 aopArg (sym_link *ftype, int i)
2223 wassert (IS_FUNC (ftype));
2225 if (IFFUNC_HASVARARGS (ftype))
2226 return 0;
2228 value *args = FUNC_ARGS(ftype);
2229 wassert (args);
2231 if (FUNC_ISZ88DK_FASTCALL (ftype))
2233 if (i != 1 || IS_STRUCT (args->type))
2234 return 0;
2236 switch (getSize (args->type))
2238 case 1:
2239 return ASMOP_L;
2240 case 2:
2241 return ASMOP_HL;
2242 case 4:
2243 return ASMOP_DEHL;
2244 default:
2245 return 0;
2249 // Old SDCC calling convention: Pass everything on the stack.
2250 if (FUNC_SDCCCALL (ftype) == 0 || FUNC_ISSMALLC (ftype) || IFFUNC_ISBANKEDCALL (ftype))
2251 return 0;
2253 wassert (FUNC_SDCCCALL (ftype) == 1);
2255 if (!FUNC_HASVARARGS (ftype))
2257 int j;
2258 value *arg;
2260 for (j = 1, arg = args; j < i; j++, arg = arg->next)
2261 wassert (arg);
2263 if (IS_STRUCT (arg->type))
2264 return 0;
2266 if (i == 1 && getSize (arg->type) == 1)
2267 return ASMOP_A;
2268 if (i == 1 && getSize (arg->type) == 2)
2269 return (IS_SM83 ? ASMOP_DE : ASMOP_HL);
2270 if (i == 1 && getSize (arg->type) == 4)
2271 return (IS_SM83 ? ASMOP_DEBC : ASMOP_HLDE);
2273 if (IS_SM83 && i == 2 && aopArg (ftype, 1) == ASMOP_A && getSize (arg->type) == 1)
2274 return ASMOP_E;
2275 if (IS_SM83 && i == 2 && aopArg (ftype, 1) == ASMOP_A && getSize (arg->type) == 2)
2276 return ASMOP_DE;
2278 if (IS_SM83 && i == 2 && aopArg (ftype, 1) == ASMOP_DE && getSize (arg->type) == 1)
2279 return ASMOP_A;
2280 if (IS_SM83 && i == 2 && aopArg (ftype, 1) == ASMOP_DE && getSize (arg->type) == 2)
2281 return ASMOP_BC;
2283 if (!IS_SM83 && i == 2 && aopArg (ftype, 1) == ASMOP_A && getSize (arg->type) == 1)
2284 return ASMOP_L;
2286 if ((IS_Z80 || IS_Z180 || IS_Z80N || IS_R800) && i == 2 && aopArg (ftype, 1) == ASMOP_A && getSize (arg->type) == 2)
2287 return ASMOP_DE;
2288 if ((IS_Z80 || IS_Z180 || IS_Z80N || IS_R800) && i == 2 && aopArg (ftype, 1) == ASMOP_HL && getSize (arg->type) == 2)
2289 return ASMOP_DE;
2291 if ((IS_RAB || IS_TLCS90 || IS_EZ80_Z80) && i == 2 && aopArg (ftype, 1) == ASMOP_A && getSize (arg->type) == 2)
2292 return ASMOP_HL;
2293 if ((IS_RAB || IS_TLCS90 || IS_EZ80_Z80) && i == 2 && aopArg (ftype, 1) == ASMOP_HL && getSize (arg->type) == 1)
2294 return ASMOP_A;
2295 if ((IS_RAB || IS_TLCS90 || IS_EZ80_Z80) && i == 2 && aopArg (ftype, 1) == ASMOP_HLDE && getSize (arg->type) == 1)
2296 return ASMOP_A;
2298 return 0;
2301 return 0;
2304 // Return true, iff ftype cleans up stack parameters.
2305 static bool
2306 isFuncCalleeStackCleanup (sym_link *ftype)
2308 wassert (IS_FUNC (ftype));
2310 const bool farg = !FUNC_HASVARARGS (ftype) && FUNC_ARGS (ftype) && IS_FLOAT (FUNC_ARGS (ftype)->type);
2311 const bool bigreturn = (getSize (ftype->next) > 4) || IS_STRUCT (ftype->next);
2312 int stackparmbytes = bigreturn * 2;
2313 for (value *arg = FUNC_ARGS(ftype); arg && !FUNC_HASVARARGS(ftype); arg = arg->next)
2315 int argsize = getSize (arg->type);
2316 if (argsize == 1 && FUNC_ISSMALLC (ftype)) // SmallC calling convention passes 8-bit stack arguments as 16 bit.
2317 argsize++;
2318 if (!SPEC_REGPARM (arg->etype))
2319 stackparmbytes += argsize;
2321 if (!stackparmbytes)
2322 return false;
2324 if (IFFUNC_ISZ88DK_CALLEE (ftype))
2325 return true;
2327 if (FUNC_SDCCCALL (ftype) == 0 || FUNC_ISSMALLC (ftype) || FUNC_ISZ88DK_FASTCALL (ftype))
2328 return false;
2330 if (IFFUNC_ISBANKEDCALL (ftype))
2331 return false;
2333 if (FUNC_HASVARARGS (ftype))
2334 return false;
2336 wassert (FUNC_SDCCCALL (ftype) == 1);
2338 // Callee cleans up stack for all non-vararg functions on sm83.
2339 if (IS_SM83)
2340 return true;
2342 // Callee cleans up stack if return value has at most 16 bits or the return value is float and there is a first argument of type float.
2343 if (!ftype->next || getSize (ftype->next) <= 2)
2344 return true;
2345 else if (IS_FLOAT (ftype->next) && farg)
2346 return true;
2347 return false;
2350 /*-----------------------------------------------------------------*/
2351 /* freeAsmop - free up the asmop given to an operand */
2352 /*----------------------------------------------------------------*/
2353 static void
2354 freeAsmop (operand * op, asmop *aaop)
2356 asmop *aop;
2358 if (!op)
2359 aop = aaop;
2360 else
2361 aop = op->aop;
2363 if (!aop)
2364 return;
2366 if (aop->freed)
2367 goto dealloc;
2369 aop->freed = 1;
2371 if (aop->type == AOP_PAIRPTR && !IS_SM83 && aop->aopu.aop_pairId == PAIR_DE)
2373 _pop (aop->aopu.aop_pairId);
2376 if (getPairId (aop) == PAIR_HL)
2378 spillPair (PAIR_HL);
2381 dealloc:
2382 /* all other cases just dealloc */
2383 if (op)
2385 op->aop = NULL;
2386 if (IS_SYMOP (op))
2388 OP_SYMBOL (op)->aop = NULL;
2389 /* if the symbol has a spill */
2390 if (SPIL_LOC (op))
2391 SPIL_LOC (op)->aop = NULL;
2397 static bool
2398 isLitWord (const asmop *aop)
2400 /* if (aop->size != 2)
2401 return FALSE; */
2402 switch (aop->type)
2404 case AOP_IMMD:
2405 case AOP_LIT:
2406 return TRUE;
2407 default:
2408 return FALSE;
2412 static const char *
2413 aopGetLitWordLong (const asmop *aop, int offset, bool with_hash)
2415 static struct dbuf_s dbuf = { 0 };
2417 if (dbuf_is_initialized (&dbuf))
2419 dbuf_set_length (&dbuf, 0);
2421 else
2423 dbuf_init (&dbuf, 128);
2426 /* depending on type */
2427 switch (aop->type)
2429 case AOP_HL:
2430 case AOP_IY:
2431 case AOP_IMMD:
2432 /* PENDING: for re-target */
2433 if (with_hash)
2435 dbuf_tprintf (&dbuf, "!hashedstr + %d", aop->aopu.aop_immd, offset);
2437 else if (offset == 0)
2439 dbuf_tprintf (&dbuf, "%s", aop->aopu.aop_immd);
2441 else
2443 dbuf_tprintf (&dbuf, "%s + %d", aop->aopu.aop_immd, offset);
2445 break;
2447 case AOP_LIT:
2449 value *val = aop->aopu.aop_lit;
2450 /* if it is a float then it gets tricky */
2451 /* otherwise it is fairly simple */
2452 if (!IS_FLOAT (val->type))
2454 unsigned long long v = ullFromVal (val);
2456 v >>= (offset * 8);
2458 dbuf_tprintf (&dbuf, with_hash ? "!immedword" : "!constword", (unsigned) (v & 0xffffu));
2460 else
2462 union
2464 float f;
2465 unsigned char c[4];
2468 unsigned int i;
2470 /* it is type float */
2471 fl.f = (float) floatFromVal (val);
2473 #ifdef WORDS_BIGENDIAN
2474 i = fl.c[3 - offset] | (fl.c[3 - offset - 1] << 8);
2475 #else
2476 i = fl.c[offset] | (fl.c[offset + 1] << 8);
2477 #endif
2478 dbuf_tprintf (&dbuf, with_hash ? "!immedword" : "!constword", i);
2481 break;
2483 case AOP_REG:
2484 case AOP_STK:
2485 case AOP_DIR:
2486 case AOP_SFR:
2487 case AOP_STL:
2488 case AOP_CRY:
2489 case AOP_EXSTK:
2490 case AOP_PAIRPTR:
2491 case AOP_DUMMY:
2492 break;
2494 default:
2495 dbuf_destroy (&dbuf);
2496 fprintf (stderr, "aop->type: %d\n", aop->type);
2497 wassertl (0, "aopGetLitWordLong got unsupported aop->type");
2498 exit (0);
2500 return dbuf_c_str (&dbuf);
2503 static bool
2504 isPtr (const char *s)
2506 if (!strcmp (s, "hl"))
2507 return TRUE;
2508 if (!strcmp (s, "ix"))
2509 return TRUE;
2510 if (!strcmp (s, "iy"))
2511 return TRUE;
2512 return FALSE;
2515 static void
2516 adjustPair (const char *pair, int *pold, int new_val)
2518 wassert (pair);
2520 while (*pold < new_val)
2522 emit2 ("inc %s", pair);
2523 (*pold)++;
2525 while (*pold > new_val)
2527 emit2 ("dec %s", pair);
2528 (*pold)--;
2532 static void
2533 spillCached (void)
2535 spillPair (PAIR_HL);
2536 spillPair (PAIR_IY);
2539 static bool
2540 requiresHL (const asmop *aop)
2542 switch (aop->type)
2544 case AOP_IY:
2545 return FALSE;
2546 case AOP_HL:
2547 case AOP_EXSTK:
2548 case AOP_STL:
2549 return true;
2550 case AOP_STK:
2551 return (IS_SM83 || _G.omitFramePtr);
2552 case AOP_REG:
2554 int i;
2555 for (i = 0; i < aop->size; i++)
2557 wassert (aop->aopu.aop_reg[i]);
2558 if (aop->aopu.aop_reg[i]->rIdx == L_IDX || aop->aopu.aop_reg[i]->rIdx == H_IDX)
2559 return TRUE;
2562 case AOP_PAIRPTR:
2563 return (aop->aopu.aop_pairId == PAIR_HL);
2564 default:
2565 return FALSE;
2569 // Updated the internally cached value for a pair.
2570 static void
2571 updatePair (PAIR_ID pairId, int diff)
2573 if (_G.pairs[pairId].last_type == AOP_LIT)
2574 _G.pairs[pairId].value = (_G.pairs[pairId].value + (unsigned int)diff) & 0xffff;
2575 else if (_G.pairs[pairId].last_type == AOP_IMMD || _G.pairs[pairId].last_type == AOP_IY || _G.pairs[pairId].last_type == AOP_HL ||
2576 _G.pairs[pairId].last_type == AOP_STK || _G.pairs[pairId].last_type == AOP_EXSTK)
2577 _G.pairs[pairId].offset += diff;
2580 // Return 0, if adjusting the old value in the pair is sufficient.
2581 static int
2582 fetchLitPair (PAIR_ID pairId, asmop *left, int offset, bool f_dead, bool dry)
2584 const char *pair = _pairs[pairId].name;
2585 char *l = Safe_strdup (aopGetLitWordLong (left, offset, FALSE));
2586 char *base_str = Safe_strdup (aopGetLitWordLong (left, 0, FALSE));
2588 // emitDebug (";fetchLitPair %s", pair);
2590 wassert (pair);
2592 const char *base = base_str;
2594 // Make offset from aopGetLitWordLong explicit.
2595 if (strchr (base_str, '+') && base_str[0] == '(' && base_str[1] == '_' && strchr (base_str, ' '))
2597 long xoffset = strtol(strchr (base_str, '+') + 1, 0, 0);
2598 if (abs(offset < 10000) && labs(xoffset) < 10000l)
2600 *(strchr (base_str, ' ')) = 0;
2601 base++;
2602 offset += xoffset;
2606 if (isPtr (pair))
2608 if (pairId == PAIR_HL || pairId == PAIR_IY)
2610 if (pairId == PAIR_HL && base[0] == '0') // Ugly workaround
2612 unsigned int tmpoffset;
2613 const char *tmpbase;
2614 if (sscanf (base, "%xd", &tmpoffset) && (tmpbase = strchr (base, '+')))
2616 offset = tmpoffset;
2617 base = tmpbase++;
2620 if ((_G.pairs[pairId].last_type == AOP_IMMD && left->type == AOP_IMMD) ||
2621 (_G.pairs[pairId].last_type == AOP_IY && left->type == AOP_IY) ||
2622 (_G.pairs[pairId].last_type == AOP_HL && left->type == AOP_HL))
2624 if (!regalloc_dry_run && _G.pairs[pairId].base && !strcmp (_G.pairs[pairId].base, base)) // Todo: Exact cost.
2626 if (pairId == PAIR_HL && abs (_G.pairs[pairId].offset - offset) < 3)
2628 if (dry) // Just report matching base
2629 return (0);
2630 adjustPair (pair, &_G.pairs[pairId].offset, offset);
2631 goto adjusted;
2633 if (pairId == PAIR_IY && offset == _G.pairs[pairId].offset)
2635 if (dry) // Just report matching base
2636 return (0);
2637 goto adjusted;
2643 if(dry)
2644 return(-1);
2646 if (pairId == PAIR_HL && left->type == AOP_LIT && _G.pairs[pairId].last_type == AOP_LIT)
2648 unsigned new_low, new_high, old_low, old_high;
2649 new_low = byteOfVal (left->aopu.aop_lit, offset);
2650 new_high = byteOfVal (left->aopu.aop_lit, offset + 1);
2651 old_low = (_G.pairs[pairId].value >> 0) & 0xff;
2652 old_high = (_G.pairs[pairId].value >> 8) & 0xff;
2654 if (new_low == old_low && new_high == old_high)
2655 goto adjusted;
2656 else if (IS_RAB && !new_high && (new_low == 1 && (old_high || old_low)) && f_dead)
2658 emit2 ("bool hl");
2659 cost (1, 2);
2660 goto adjusted;
2662 else if (new_high == old_high && new_low == old_high)
2664 emit3_o (A_LD, ASMOP_L, 0, ASMOP_H, 0);
2665 goto adjusted;
2667 else if (new_low == old_low && new_high == old_low)
2669 emit3_o (A_LD, ASMOP_H, 0, ASMOP_L, 0);
2670 goto adjusted;
2672 /* Change lower byte only. */
2673 else if (new_high == old_high)
2675 emit3_o (A_LD, ASMOP_L, 0, left, offset);
2676 goto adjusted;
2678 /* Change upper byte only. */
2679 else if (new_low == old_low)
2681 emit3_o (A_LD, ASMOP_H, 0, left, offset + 1);
2682 goto adjusted;
2687 if(dry)
2688 return(-1);
2690 /* Both a lit on the right and a true symbol on the left */
2691 if (IS_RAB && pairId == PAIR_HL && left->type == AOP_LIT && !byteOfVal (left->aopu.aop_lit, offset + 1) && !byteOfVal (left->aopu.aop_lit, offset) && f_dead)
2693 emit2 ("bool hl");
2694 emit2 ("ld l, h");
2695 cost (1 + 1, 2 + 2);
2697 else
2699 emit2 ("ld %s, !hashedstr", pair, l);
2700 if (pairId == PAIR_IX || pairId == PAIR_IY)
2701 cost2 (4 - IS_TLCS90 , 14, 12, 8, 12, 6, 4, 4);
2702 else
2703 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
2706 adjusted:
2707 _G.pairs[pairId].last_type = left->type;
2708 if (left->type == AOP_LIT)
2709 _G.pairs[pairId].value = byteOfVal (left->aopu.aop_lit, offset) + (byteOfVal (left->aopu.aop_lit, offset + 1) << 8);
2710 else
2711 _G.pairs[pairId].base = traceAlloc (&_G.trace.aops, Safe_strdup (base));
2712 _G.pairs[pairId].offset = offset;
2713 Safe_free (base_str);
2714 Safe_free (l);
2716 return(0);
2719 static PAIR_ID
2720 makeFreePairId (const iCode * ic, bool * pisUsed)
2722 *pisUsed = FALSE;
2724 if (ic != NULL)
2726 if (!bitVectBitValue (ic->rMask, B_IDX) && !bitVectBitValue (ic->rMask, C_IDX))
2728 return PAIR_BC;
2730 else if (!IS_SM83 && !bitVectBitValue (ic->rMask, D_IDX) && !bitVectBitValue (ic->rMask, E_IDX))
2732 return PAIR_DE;
2734 else
2736 *pisUsed = TRUE;
2737 return PAIR_HL;
2740 else
2742 *pisUsed = TRUE;
2743 return PAIR_HL;
2747 static void
2748 genMove_o (asmop *result, int roffset, asmop *source, int soffset, int size, bool a_dead_global, bool hl_dead_global, bool de_dead_global, bool iy_dead_global, bool f_dead);
2750 /* If ic != 0, we can safely use isPairDead(). */
2751 /* By now, genMove / genMove_o is as good or better than this for nearly all uses. */
2752 static void
2753 fetchPairLong (PAIR_ID pairId, asmop *aop, const iCode *ic, int offset)
2755 emitDebug (";fetchPairLong");
2757 if (aop->type == AOP_STL && !offset)
2759 if (IS_SM83 && pairId == PAIR_DE || pairId == PAIR_BC)
2761 _push (PAIR_HL);
2762 emit2 ("ld hl, !immed%d", spOffset(aop->aopu.aop_stk));
2763 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
2764 emit2 ("add hl, sp");
2765 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
2766 emit2 ("ld %s, l", _pairs[pairId].l);
2767 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
2768 emit2 ("ld %s, h", _pairs[pairId].h);
2769 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
2770 _pop (PAIR_HL);
2771 return;
2773 else if (pairId == PAIR_IY)
2775 emit2 ("ld iy, !immed%d", spOffset(aop->aopu.aop_stk));
2776 emit2 ("add iy, sp");
2777 cost2 (6 - IS_TLCS90, 29, 22, 12, 0, 14, 6, 6);
2778 return;
2781 if (pairId == PAIR_DE)
2782 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
2783 emit2 ("ld hl, !immed%d", spOffset(aop->aopu.aop_stk));
2784 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
2785 emit2 ("add hl, sp");
2786 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
2787 if (pairId == PAIR_DE)
2788 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
2789 spillPair (pairId);
2790 return;
2792 else if (aop->type == AOP_STL && offset >= 2)
2794 fetchLitPair (pairId, ASMOP_ZERO, 0, true, false);
2795 return;
2797 else if (aop->type == AOP_STL)
2799 UNIMPLEMENTED;
2800 return;
2803 /* if this is rematerializable */
2804 if (isLitWord (aop))
2805 fetchLitPair (pairId, aop, offset, true, false);
2806 else
2808 if (getPairId_o (aop, offset) == pairId)
2810 /* Do nothing */
2812 else if (IS_EZ80_Z80 && aop->size - offset >= 2 && aop->type == AOP_STK)
2814 int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2815 emit2 ("ld %s, %d (ix)", _pairs[pairId].name, fp_offset);
2816 cost (3, 5);
2818 /* 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).
2819 SM83 is nearly twice as fast doing it byte by byte, but that's a byte bigger.
2820 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). */
2821 else if (!IS_RAB && (!IS_SM83 || optimize.codeSize) && aop->size - offset >= 2 &&
2822 (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (!regalloc_dry_run || aop->aopu.aop_stk > 0)
2823 && (aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) +
2824 _G.stack.pushed) == 2 && ic && getFreePairId (ic) != PAIR_INVALID && getFreePairId (ic) != pairId)
2826 PAIR_ID extrapair = getFreePairId (ic);
2827 _pop (extrapair);
2828 _pop (pairId);
2829 _push (pairId);
2830 _push (extrapair);
2832 /* Todo: Use even cheaper ex hl, (sp) and ex iy, (sp) when possible. */
2833 else if ((!IS_RAB || pairId == PAIR_BC || pairId == PAIR_DE) && aop->size - offset >= 2 &&
2834 (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (!regalloc_dry_run || aop->aopu.aop_stk > 0)
2835 && (aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) +
2836 _G.stack.pushed) == 0)
2838 _pop (pairId);
2839 _push (pairId);
2841 else if (!IS_SM83 && (aop->type == AOP_IY || aop->type == AOP_HL) &&
2842 (aop->size >= 2 || pairId != PAIR_IY && optimize.allow_unsafe_read))
2844 /* Instead of fetching relative to IY, just grab directly
2845 from the address IY refers to */
2846 emit2 ("ld %s, !mems", _pairs[pairId].name, aopGetLitWordLong (aop, offset, FALSE));
2847 if (pairId == PAIR_HL)
2848 cost2 (3 + IS_TLCS90, 16, 15, 11, 0, 12, 5, 5);
2849 else
2850 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
2852 if (aop->size < 2)
2854 emit2 ("ld %s, !zero", _pairs[pairId].h);
2855 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
2858 /* we need to get it byte by byte */
2859 else if (pairId == PAIR_HL && (IS_SM83 || IY_RESERVED) && (aop->type == AOP_HL || aop->type == AOP_EXSTK || IS_SM83 && aop->type == AOP_STK) && requiresHL (aop))
2861 if (!regalloc_dry_run) // TODO: Fix this to get correct cost!
2862 aopGet (aop, offset, FALSE);
2863 switch (aop->size - offset)
2865 case 1:
2866 emit2 ("ld l, !*hl");
2867 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
2868 emit2 ("ld h, !immedbyte", 0u);
2869 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
2870 break;
2871 default:
2872 wassertl (aop->size - offset > 1, "Attempted to fetch no data into HL");
2873 if (IS_RAB)
2875 emit2 ("ld hl, 0 (hl)");
2876 cost (3, 11);
2878 else if (IS_EZ80_Z80 || IS_TLCS90)
2880 emit2 ("ld hl, !*hl");
2881 cost2 (2, 0, 0, 0, 0, 8, 4, 0);
2883 else
2885 if (ic && bitVectBitValue (ic->rMask, A_IDX))
2886 _push (PAIR_AF);
2888 emit2 ("!ldahli");
2889 if (IS_SM83)
2890 cost (1, 8); // ldi
2891 else
2893 cost2 (1, 7, 6, 5, 8, 6, 2, 2); // ld , a(hl)
2894 cost2 (1, 6, 4, 2, 8, 4, 1, 1); // inc hl
2896 emit2 ("ld h, !*hl");
2897 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
2898 emit3 (A_LD, ASMOP_L, ASMOP_A);
2900 if (ic && bitVectBitValue (ic->rMask, A_IDX))
2901 _pop (PAIR_AF);
2903 break;
2906 else if (pairId == PAIR_IY)
2908 /* The Rabbit has the ld iy, n (sp) instruction. */
2909 int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2910 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
2911 if ((IS_RAB || IS_TLCS90) && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && abs (sp_offset) <= 127)
2913 emit2 ("ld iy, %d (sp)", sp_offset);
2914 cost2 (3, 0, 0, 11, 0, 12, 0, 0);
2916 else if (isPair (aop) && (IS_RAB || IS_TLCS90) && getPairId (aop) == PAIR_HL)
2918 emit2 ("ld iy, hl");
2919 cost2 (1 + IS_RAB, 0, 0, 4, 0, 6, 0, 0);
2921 else if (isPair (aop))
2923 _push (getPairId (aop));
2924 _pop (PAIR_IY);
2926 else
2928 bool isUsed;
2929 PAIR_ID id = makeFreePairId (ic, &isUsed);
2930 if (isUsed)
2931 _push (id);
2932 /* Can't load into parts, so load into HL then exchange. */
2933 genMove_o (id == PAIR_HL ? ASMOP_HL : id == PAIR_DE ? ASMOP_DE : id == PAIR_BC ? ASMOP_BC : ASMOP_IY, 0, aop, offset, 2, false, false, false, false, false);
2935 if ((IS_RAB || IS_TLCS90) && id == PAIR_HL)
2937 emit2 ("ld iy, hl");
2938 cost2 (1 + IS_RAB, 0, 0, 4, 0, 6, 0, 0);
2940 else
2942 _push (id);
2943 _pop (PAIR_IY);
2945 if (isUsed)
2946 _pop (id);
2949 else if (isUnsplitable (aop))
2951 _push (getPairId (aop));
2952 _pop (pairId);
2954 else
2956 /* The Rabbit has the ld hl, n (sp) and ld hl, n (ix) instructions. */
2957 int fp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
2958 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
2959 if ((IS_RAB || IS_TLCS90) && aop->size - offset >= 2 && (aop->type == AOP_STK || aop->type == AOP_EXSTK)
2960 && (pairId == PAIR_HL || pairId == PAIR_IY || pairId == PAIR_DE) && (abs (fp_offset) <= 127 && pairId == PAIR_HL
2961 && aop->type == AOP_STK
2962 || abs (sp_offset) <= 127))
2964 if (pairId == PAIR_DE && !(ic && isPairDead (PAIR_HL, ic)))
2965 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
2966 if (abs (sp_offset) <= 127)
2967 emit2 ("ld %s, %d (sp)", pairId == PAIR_IY ? "iy" : "hl", sp_offset); /* Fetch relative to stack pointer. */
2968 else
2969 emit2 ("ld hl, %d (ix)", fp_offset); /* Fetch relative to frame pointer. */
2970 cost (pairId == PAIR_IY ? 3 : 2, pairId == PAIR_IY ? 11 : 9);
2971 if (pairId == PAIR_DE)
2972 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
2974 /* Operand resides (partially) in the pair */
2975 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
2977 _moveA3 (aop, offset);
2978 if (!regalloc_dry_run)
2979 emit2 ("ld %s, %s", _pairs[pairId].h, aopGet (aop, offset + 1, FALSE));
2980 ld_cost (pairId == PAIR_HL ? ASMOP_H : pairId == PAIR_DE ? ASMOP_D : ASMOP_B, 0, aop, offset + 1, true);
2981 emit2 ("ld %s, a", _pairs[pairId].l);
2982 ld_cost (ASMOP_L, 0, ASMOP_A, 0, true);
2984 /* The Rabbit's cast to bool is a cheap way of zeroing h (similar to xor a, a for a for the Z80). */
2985 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)))
2987 emit2 ("bool hl");
2988 cost (1, 2);
2989 if (!regalloc_dry_run)
2990 emit2 ("ld %s, %s", _pairs[pairId].l, aopGet (aop, offset, false));
2991 ld_cost (pairId == PAIR_HL ? ASMOP_L : pairId == PAIR_DE ? ASMOP_E : ASMOP_C, 0, aop, offset, true);
2993 else
2995 if (pairId == PAIR_HL && (aopInReg (aop, offset, IYL_IDX) || aopInReg (aop, offset, IYH_IDX)))
2996 UNIMPLEMENTED;
2997 if (!aopInReg (aop, offset, _pairs[pairId].l_idx))
2999 if (!HAS_IYL_INST && (aopInReg (aop, offset, IYL_IDX) || aopInReg (aop, offset, IYH_IDX)))
3000 UNIMPLEMENTED;
3001 if (!regalloc_dry_run)
3002 emit2 ("ld %s, %s", _pairs[pairId].l, aopGet (aop, offset, false));
3003 ld_cost (pairId == PAIR_HL ? ASMOP_L : pairId == PAIR_DE ? ASMOP_E : ASMOP_C, 0, aop, offset, true);
3005 if (pairId == PAIR_HL && (aopInReg (aop, offset + 1, IYL_IDX) || aopInReg (aop, offset + 1, IYH_IDX)))
3006 UNIMPLEMENTED;
3007 if (!aopInReg (aop, offset + 1, _pairs[pairId].h_idx))
3009 if (!HAS_IYL_INST && (aopInReg (aop, offset + 1, IYL_IDX) || aopInReg (aop, offset + 1, IYH_IDX)))
3010 UNIMPLEMENTED;
3011 if (!regalloc_dry_run)
3012 emit2 ("ld %s, %s", _pairs[pairId].h, aopGet (aop, offset + 1, false));
3013 ld_cost (pairId == PAIR_HL ? ASMOP_H : pairId == PAIR_DE ? ASMOP_D : ASMOP_B, 0, aop, offset + 1, true);
3017 /* PENDING: check? */
3018 spillPair (pairId);
3022 static void
3023 fetchPair (PAIR_ID pairId, asmop *aop)
3025 fetchPairLong (pairId, aop, NULL, 0);
3028 static void
3029 setupPairFromSP (PAIR_ID id, int offset)
3031 wassertl (id == PAIR_HL || id == PAIR_DE || id == PAIR_IY, "Setup relative to SP only implemented for HL, DE, IY");
3033 if (_G.preserveCarry)
3035 _push (PAIR_AF);
3036 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
3037 offset += 2;
3040 if (id == PAIR_DE && !IS_SM83) // TODO: Could hl be in use for sm83, so it needs to be saved and restored?
3041 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3043 if (offset < INT8MIN || offset > INT8MAX || id == PAIR_IY)
3045 struct dbuf_s dbuf;
3046 PAIR_ID lid = (id == PAIR_DE) ? PAIR_HL : id;
3047 dbuf_init (&dbuf, sizeof(int) * 3 + 1);
3048 dbuf_printf (&dbuf, "%d", offset);
3049 emit2 ("ld %s, !hashedstr", _pairs[lid].name, dbuf_c_str (&dbuf));
3050 if (lid == PAIR_IY)
3051 cost2 (4 - IS_TLCS90, 14, 12, 8, 0, 6, 4, 4);
3052 else
3053 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
3054 dbuf_destroy (&dbuf);
3055 emit2 ("add %s, sp", _pairs[lid].name);
3056 if (lid == PAIR_IY)
3057 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
3058 else
3059 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
3061 else
3063 wassert (id == PAIR_DE || id == PAIR_HL);
3064 emit2 ("!ldahlsp", offset);
3065 if (IS_SM83)
3066 cost (2, 12);
3067 else
3069 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
3070 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
3074 if (id == PAIR_DE && !IS_SM83)
3075 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3076 else if (id == PAIR_DE)
3078 genMovePairPair (PAIR_HL, PAIR_DE);
3079 spillPair (PAIR_HL);
3082 if (_G.preserveCarry)
3084 _pop (PAIR_AF);
3085 cost2 (1, 10, 9, 7, 12, 6, 3, 3);
3086 offset -= 2;
3089 spillPair (id);
3092 static void
3093 shiftIntoPair (PAIR_ID id, asmop *aop);
3095 /*-----------------------------------------------------------------*/
3096 /* pointPairToAop() make a register pair point to a byte of an aop */
3097 /*-----------------------------------------------------------------*/
3098 static void pointPairToAop (PAIR_ID pairId, const asmop *aop, int offset)
3100 switch (aop->type)
3102 case AOP_EXSTK:
3103 wassertl (!IS_SM83, "The SM83 doesn't have an extended stack");
3105 case AOP_STK:
3106 ; int abso = aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3108 if ((_G.pairs[pairId].last_type == AOP_STK || _G.pairs[pairId].last_type == AOP_EXSTK) && abs (_G.pairs[pairId].offset - abso) < (_G.preserveCarry ? 5 : 3))
3109 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
3110 else
3111 setupPairFromSP (pairId, abso + _G.stack.pushed);
3113 _G.pairs[pairId].offset = abso;
3115 break;
3117 // Legacy.
3118 case AOP_HL:
3119 case AOP_IY:
3120 fetchLitPair (pairId, (asmop *) aop, offset, true, false);
3121 _G.pairs[pairId].offset = offset;
3122 break;
3124 case AOP_PAIRPTR:
3125 wassert (!offset);
3127 shiftIntoPair (pairId, (asmop *) aop); // Legacy. Todo: eliminate uses of shiftIntoPair() ?
3129 break;
3131 default:
3132 wassertl (0, "Unsupported aop type for pointPairToAop()");
3135 _G.pairs[pairId].last_type = aop->type;
3138 // Weird function. Sometimes offset is used, sometimes not.
3139 // Callers rely on that behaviour. Uses of this should be replaced
3140 // by pointPairToAop() above after the 3.7.0 release.
3141 static void
3142 setupPair (PAIR_ID pairId, asmop *aop, int offset)
3144 switch (aop->type)
3146 case AOP_IY:
3147 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "AOP_IY must be in IY or HL");
3148 fetchLitPair (pairId, aop, 0, true, false);
3149 break;
3151 case AOP_HL:
3152 wassertl (pairId == PAIR_HL, "AOP_HL must be in HL");
3154 fetchLitPair (pairId, aop, offset, true, false);
3155 _G.pairs[pairId].offset = offset;
3156 break;
3158 case AOP_EXSTK:
3159 wassertl (!IS_SM83, "The SM83 doesn't have an extended stack");
3160 wassertl (pairId == PAIR_IY || pairId == PAIR_HL, "The Z80 extended stack must be in IY or HL");
3163 int offset = aop->aopu.aop_stk + _G.stack.offset;
3165 if (aop->aopu.aop_stk >= 0)
3166 offset += _G.stack.param_offset;
3168 if (_G.pairs[pairId].last_type == aop->type && abs(_G.pairs[pairId].offset - offset) <= 3)
3169 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
3170 else
3172 struct dbuf_s dbuf;
3174 /* PENDING: Do this better. */
3175 if (_G.preserveCarry)
3176 _push (PAIR_AF);
3177 dbuf_init (&dbuf, 128);
3178 dbuf_printf (&dbuf, "%d", offset + _G.stack.pushed);
3179 emit2 ("ld %s, !hashedstr", _pairs[pairId].name, dbuf_c_str (&dbuf));
3180 dbuf_destroy (&dbuf);
3181 emit2 ("add %s, sp", _pairs[pairId].name);
3182 _G.pairs[pairId].last_type = aop->type;
3183 _G.pairs[pairId].offset = offset;
3184 if (_G.preserveCarry)
3185 _pop (PAIR_AF);
3188 break;
3190 case AOP_STK:
3192 /* Doesnt include _G.stack.pushed */
3193 int abso = aop->aopu.aop_stk + offset + _G.stack.offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3195 assert (pairId == PAIR_HL);
3196 /* In some cases we can still inc or dec hl */
3197 if (_G.pairs[pairId].last_type == AOP_STK && abs (_G.pairs[pairId].offset - abso) < 3)
3199 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, abso);
3201 else
3203 setupPairFromSP (PAIR_HL, abso + _G.stack.pushed);
3205 _G.pairs[pairId].offset = abso;
3206 break;
3209 case AOP_PAIRPTR:
3210 if (pairId != aop->aopu.aop_pairId)
3211 genMovePairPair (aop->aopu.aop_pairId, pairId);
3212 adjustPair (_pairs[pairId].name, &_G.pairs[pairId].offset, offset);
3213 break;
3215 default:
3216 wassert (0);
3218 _G.pairs[pairId].last_type = aop->type;
3221 static void
3222 emitLabelSpill (symbol *tlbl)
3224 emitLabel (tlbl);
3225 spillCached ();
3228 /*-----------------------------------------------------------------*/
3229 /* aopGet - for fetching value of the aop */
3230 /*-----------------------------------------------------------------*/
3231 static const char *
3232 aopGet (asmop *aop, int offset, bool bit16)
3234 static struct dbuf_s dbuf = { 0 };
3236 wassert_bt (!regalloc_dry_run);
3238 if (dbuf_is_initialized (&dbuf))
3240 /* reuse the dynamically allocated buffer */
3241 dbuf_set_length (&dbuf, 0);
3243 else
3245 /* first time: initialize the dynamically allocated buffer */
3246 dbuf_init (&dbuf, 128);
3249 /* offset is greater than size then zero */
3250 /* PENDING: this seems a bit screwed in some pointer cases. */
3251 if (offset > (aop->size - 1) && aop->type != AOP_LIT)
3253 dbuf_tprintf (&dbuf, "!zero");
3255 else
3257 /* depending on type */
3258 switch (aop->type)
3260 case AOP_DUMMY:
3261 dbuf_tprintf (&dbuf, bit16 ? "hl" : "a");
3262 break;
3264 case AOP_IMMD:
3265 /* PENDING: re-target */
3266 if (bit16)
3267 dbuf_tprintf (&dbuf, "!immedword", aop->aopu.aop_immd);
3268 else
3270 switch (offset)
3272 case 2:
3273 // dbuf_tprintf (&dbuf, "!bankimmeds", aop->aopu.aop_immd); Bank support not fully implemented yet.
3274 dbuf_tprintf (&dbuf, "!zero");
3275 break;
3277 case 1:
3278 dbuf_tprintf (&dbuf, "!msbimmeds", aop->aopu.aop_immd);
3279 break;
3281 case 0:
3282 dbuf_tprintf (&dbuf, "!lsbimmeds", aop->aopu.aop_immd);
3283 break;
3285 default:
3286 dbuf_tprintf (&dbuf, "!zero");
3289 break;
3291 case AOP_DIR:
3292 wassert (IS_SM83);
3293 emit2 ("ld a, (%s+%d)", aop->aopu.aop_dir, offset);
3294 cost2 (3, 13, 12, 9, 16, 10, 4, 4);
3295 dbuf_append_char (&dbuf, 'a');
3296 break;
3298 case AOP_SFR:
3299 wassertl (!IS_TLCS90, "TLCS-90 does not have a separate I/O space");
3300 if (IS_SM83)
3302 emit2 ("!rldh", aop->aopu.aop_dir, offset);
3303 cost (2, 12);
3304 dbuf_append_char (&dbuf, 'a');
3306 else if (IS_RAB)
3308 emit2 ("ioi");
3309 emit2 ("ld a, !mems", aop->aopu.aop_dir);
3310 emit2 ("nop"); /* Workaround for Rabbit 2000 hardware bug. see TN302 for details. */
3311 dbuf_append_char (&dbuf, 'a');
3313 else
3315 /*.p.t.20030716 handling for i/o port read access for Z80 */
3316 if (aop->paged)
3318 /* banked mode */
3319 /* reg A goes to address bits 15-8 during "in a,(x)" instruction */
3320 emit2 ("ld a, !msbimmeds", aop->aopu.aop_dir);
3321 emit2 ("in a, (!lsbimmeds)", aop->aopu.aop_dir);
3323 else if (z80_opts.port_mode == 180)
3325 /* z180 in0/out0 mode */
3326 emit2 ("in0 a, !mems", aop->aopu.aop_dir);
3328 else
3330 /* 8 bit mode */
3331 emit2 ("in a, !mems", aop->aopu.aop_dir);
3332 cost2 (2, 11, 9, 0, 0, 0, 3, 3);
3335 dbuf_append_char (&dbuf, 'a');
3337 break;
3339 case AOP_REG:
3340 if (bit16)
3342 if (aopInReg (aop, offset, IY_IDX))
3343 dbuf_append_str (&dbuf, "iy");
3344 else
3346 dbuf_append_str (&dbuf, aop->aopu.aop_reg[offset + 1]->name);
3347 dbuf_append_str (&dbuf, aop->aopu.aop_reg[offset]->name);
3350 else
3351 dbuf_append_str (&dbuf, aop->aopu.aop_reg[offset]->name);
3352 break;
3354 case AOP_HL:
3355 setupPair (PAIR_HL, aop, offset);
3356 dbuf_tprintf (&dbuf, "!*hl");
3357 break;
3359 case AOP_IY:
3360 wassert (!IS_SM83);
3361 setupPair (PAIR_IY, aop, offset);
3362 dbuf_tprintf (&dbuf, "!*iyx", offset);
3363 break;
3365 case AOP_EXSTK:
3366 if (!IY_RESERVED)
3368 wassert (!IS_SM83);
3369 setupPair (PAIR_IY, aop, offset);
3370 dbuf_tprintf (&dbuf, "!*iyx", offset);
3371 break;
3374 case AOP_STK:
3375 if (IS_TLCS90) // Try to use (sp) addressing mode.
3377 int sp_offset = aop->aopu.aop_stk + offset + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) + _G.stack.pushed + _G.stack.offset;
3379 if (!sp_offset)
3381 dbuf_tprintf (&dbuf, "(sp)");
3382 break;
3386 if (IS_SM83 || aop->type == AOP_EXSTK)
3388 pointPairToAop (PAIR_HL, aop, offset);
3389 dbuf_tprintf (&dbuf, "!*hl");
3391 else if (_G.omitFramePtr)
3393 if (aop->aopu.aop_stk >= 0)
3394 offset += _G.stack.param_offset;
3395 setupPair (PAIR_IX, aop, offset);
3396 dbuf_tprintf (&dbuf, "!*ixx", offset);
3398 else
3400 if (aop->aopu.aop_stk >= 0)
3401 offset += _G.stack.param_offset;
3402 dbuf_tprintf (&dbuf, "!*ixx", aop->aopu.aop_stk + offset);
3404 break;
3406 case AOP_CRY:
3407 wassertl (0, "Tried to fetch from a bit variable");
3408 break;
3410 case AOP_LIT:
3411 dbuf_append_str (&dbuf, aopLiteralLong (aop->aopu.aop_lit, offset, 1 + bit16));
3412 break;
3414 case AOP_PAIRPTR:
3415 setupPair (aop->aopu.aop_pairId, aop, offset);
3416 if (aop->aopu.aop_pairId == PAIR_IX)
3417 dbuf_tprintf (&dbuf, "!*ixx", offset);
3418 else if (aop->aopu.aop_pairId == PAIR_IY)
3419 dbuf_tprintf (&dbuf, "!*iyx", offset);
3420 else
3421 dbuf_tprintf (&dbuf, "!mems", _pairs[aop->aopu.aop_pairId].name);
3422 break;
3424 default:
3425 dbuf_destroy (&dbuf);
3426 fprintf (stderr, "aop->type: %d\n", aop->type);
3427 wassertl (0, "aopGet got unsupported aop->type");
3428 exit (0);
3431 return dbuf_c_str (&dbuf);
3434 static bool
3435 isRegString (const char *s)
3437 if (!strcmp (s, "b") || !strcmp (s, "c") || !strcmp (s, "d") || !strcmp (s, "e") ||
3438 !strcmp (s, "a") || !strcmp (s, "h") || !strcmp (s, "l"))
3439 return TRUE;
3440 return FALSE;
3443 static bool
3444 isConstantString (const char *s)
3446 /* This is a bit of a hack... */
3447 return (*s == '#' || *s == '$');
3450 #define AOP_NEEDSACC(x) ((x)->aop && (((x)->aop->type == AOP_CRY) || ((x)->aop->type == AOP_SFR)))
3451 #define AOP_IS_PAIRPTR(x, p) ((x)->aop->type == AOP_PAIRPTR && (x)->aop->aopu.aop_pairId == (p))
3453 static bool
3454 canAssignToPtr (const char *s)
3456 if (isRegString (s))
3457 return TRUE;
3458 if (isConstantString (s))
3459 return TRUE;
3460 return FALSE;
3463 static bool
3464 canAssignToPtr3 (const asmop *aop)
3466 if (aop->type == AOP_REG)
3467 return (TRUE);
3468 if (aop->type == AOP_IMMD || aop->type == AOP_LIT)
3469 return (TRUE);
3470 return (FALSE);
3473 /*-----------------------------------------------------------------*/
3474 /* aopPut - puts a string for a aop */
3475 /*-----------------------------------------------------------------*/
3476 static void
3477 aopPut (asmop *aop, const char *s, int offset)
3479 struct dbuf_s dbuf;
3481 wassert (!regalloc_dry_run);
3483 if (aop->size && offset > (aop->size - 1))
3485 werror_bt (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got offset > aop->size");
3486 exit (0);
3489 // PENDING
3490 dbuf_init (&dbuf, 128);
3491 dbuf_tprintf (&dbuf, s);
3492 s = dbuf_c_str (&dbuf);
3494 /* will assign value to value */
3495 /* depending on where it is of course */
3496 switch (aop->type)
3498 case AOP_DUMMY:
3499 _moveA (s); /* in case s is volatile */
3500 break;
3502 case AOP_DIR:
3503 /* Direct. Hmmm. */
3504 wassert (IS_SM83);
3505 if (strcmp (s, "a"))
3506 emit2 ("ld a, %s", s);
3507 emit2 ("ld (%s+%d),a", aop->aopu.aop_dir, offset);
3508 break;
3510 case AOP_SFR:
3511 wassertl (!IS_TLCS90, "TLCS-90 does not have a separate I/O space");
3512 if (IS_SM83)
3514 // wassert (IS_SM83);
3515 if (strcmp (s, "a"))
3516 emit2 ("ld a, %s", s);
3517 emit2 ("!lldh", aop->aopu.aop_dir, offset);
3519 else if (IS_RAB)
3521 if (strcmp (s, "a"))
3522 emit2 ("ld a, %s", s);
3524 /* LM 20110928: Need to fix to emit either "ioi" or "ioe"
3525 * (for internal vs. external I/O space
3527 emit2 ("ioi");
3528 emit2 ("ld !mems,a", aop->aopu.aop_dir);
3529 emit2 ("nop"); /* Workaround for Rabbit 2000 hardware bug. see TN302 for details. */
3531 else
3533 /*.p.t.20030716 handling for i/o port read access for Z80 */
3534 if (aop->paged)
3536 /* banked mode */
3537 if (aop->bcInUse)
3538 emit2 ("push bc");
3540 if (strlen (s) != 1 || (s[0] != 'a' && s[0] != 'd' && s[0] != 'e' && s[0] != 'h' && s[0] != 'l'))
3542 emit2 ("ld a, %s", s);
3543 s = "a";
3546 emit2 ("ld bc, !hashedstr", aop->aopu.aop_dir);
3547 emit2 ("out (c), %s", s);
3549 if (aop->bcInUse)
3550 emit2 ("pop bc");
3551 else
3552 spillPair (PAIR_BC);
3554 else if (z80_opts.port_mode == 180)
3556 /* z180 in0/out0 mode */
3557 emit2 ("ld a, %s", s);
3558 emit2 ("out0 (%s), a", aop->aopu.aop_dir);
3560 else
3562 /* 8 bit mode */
3563 if (strcmp (s, "a"))
3564 emit2 ("ld a, %s", s);
3565 emit2 ("out (%s), a", aop->aopu.aop_dir);
3568 break;
3570 case AOP_REG:
3571 if (!strcmp (aop->aopu.aop_reg[offset]->name, s))
3573 else if (!strcmp (s, "!*hl"))
3574 emit2 ("ld %s,!*hl", aop->aopu.aop_reg[offset]->name);
3575 else
3576 emit2 ("ld %s, %s", aop->aopu.aop_reg[offset]->name, s);
3577 spillPairReg (aop->aopu.aop_reg[offset]->name);
3578 break;
3580 case AOP_IY:
3581 wassert (!IS_SM83);
3582 if (!canAssignToPtr (s))
3584 emit2 ("ld a, %s", s);
3585 setupPair (PAIR_IY, aop, offset);
3586 emit2 ("ld !*iyx, a", offset);
3588 else
3590 setupPair (PAIR_IY, aop, offset);
3591 emit2 ("ld !*iyx, %s", offset, s);
3593 break;
3595 case AOP_HL:
3596 //wassert (IS_SM83);
3597 /* PENDING: for re-target */
3598 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
3600 emit2 ("ld a, !*hl");
3601 s = "a";
3603 else if (strstr (s, "(ix)") || strstr (s, "(iy)"))
3605 emit2 ("ld a, %s", s);
3606 s = "a";
3608 setupPair (PAIR_HL, aop, offset);
3610 emit2 ("ld !*hl, %s", s);
3611 break;
3613 case AOP_EXSTK:
3614 if(!IY_RESERVED)
3616 wassert (!IS_SM83);
3617 if (!canAssignToPtr (s))
3619 emit2 ("ld a, %s", s);
3620 setupPair (PAIR_IY, aop, offset);
3621 emit2 ("ld !*iyx, a", offset);
3623 else
3625 setupPair (PAIR_IY, aop, offset);
3626 emit2 ("ld !*iyx, %s", offset, s);
3628 break;
3631 case AOP_STK:
3632 if (IS_SM83 || aop->type == AOP_EXSTK)
3634 /* PENDING: re-target */
3635 if (!strcmp (s, "!*hl") || !strcmp (s, "(hl)") || !strcmp (s, "[hl]"))
3637 emit2 ("ld a, !*hl");
3638 s = "a";
3640 pointPairToAop (PAIR_HL, aop, offset);
3641 if (!canAssignToPtr (s))
3643 emit2 ("ld a, %s", s);
3644 emit2 ("ld !*hl, a");
3646 else
3647 emit2 ("ld !*hl, %s", s);
3649 else
3651 if (aop->aopu.aop_stk >= 0)
3652 offset += _G.stack.param_offset;
3653 if (!canAssignToPtr (s))
3655 emit2 ("ld a, %s", s);
3656 emit2 ("ld !*ixx, a", aop->aopu.aop_stk + offset);
3658 else
3660 emit2 ("ld !*ixx, %s", aop->aopu.aop_stk + offset, s);
3663 break;
3665 case AOP_CRY:
3666 /* if bit variable */
3667 if (!aop->aopu.aop_dir)
3669 emit2 ("ld a, !zero");
3670 emit2 ("rla");
3672 else
3674 /* In bit space but not in C - cant happen */
3675 wassertl (0, "Tried to write into a bit variable");
3677 break;
3679 case AOP_PAIRPTR:
3680 setupPair (aop->aopu.aop_pairId, aop, offset);
3681 if (aop->aopu.aop_pairId == PAIR_IX)
3682 emit2 ("ld !*ixx, %s", 0, s);
3683 else if (aop->aopu.aop_pairId == PAIR_IY)
3684 emit2 ("ld !*iyx, %s", 0, s);
3685 else
3686 emit2 ("ld !mems, %s", _pairs[aop->aopu.aop_pairId].name, s);
3687 break;
3689 default:
3690 dbuf_destroy (&dbuf); fprintf (stderr, "AOP_DIR: %d\n",AOP_DIR);
3691 fprintf (stderr, "aop->type: %d\n", aop->type);
3692 werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "aopPut got unsupported aop->type");
3693 exit (0);
3695 dbuf_destroy (&dbuf);
3698 // pop a register pair while not destroying one of the two registers in it (destroying tempreg instead, if available).
3699 static void
3700 poppairwithsavedreg (PAIR_ID pair, short survivingreg, short tempreg)
3702 if (tempreg >= 0)
3704 emit2 ("ld %s, %s", regsZ80[tempreg].name, regsZ80[survivingreg].name);
3705 ld_cost (ASMOP_L, 0, ASMOP_H, 0, true);
3706 _pop (pair);
3707 emit2 ("ld %s, %s", regsZ80[survivingreg].name, regsZ80[tempreg].name);
3708 ld_cost (ASMOP_L, 0, ASMOP_H, 0, true);
3709 return;
3712 // No tempreg, need to do it the hard way via stack access.
3713 bool isupperbyte = (survivingreg == B_IDX || survivingreg == D_IDX || survivingreg == H_IDX || survivingreg == IYH_IDX);
3714 _push (PAIR_AF); // Save flags
3715 _push (PAIR_HL); // Save hl
3716 emit2 ("ld hl, !immedword", 4 + isupperbyte);
3717 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
3718 emit2 ("add hl, sp");
3719 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
3720 emit2 ("ld (hl), %s", regsZ80[survivingreg].name);
3721 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
3722 _pop (PAIR_HL);
3723 _pop (PAIR_AF);
3724 _pop (pair);
3727 // Move, but try not to. Preserves flags. Cannot use xor to zero, since xor resets the carry flag.
3728 static void
3729 cheapMove (asmop *to, int to_offset, asmop *from, int from_offset, bool a_dead)
3731 #if 0
3732 emitDebug ("; cheapMove");
3733 #endif
3735 if (aopInReg (to, to_offset, A_IDX))
3736 a_dead = true;
3738 if (from->type == AOP_STL)
3740 if (from_offset > 2)
3742 cheapMove (to, to_offset, ASMOP_ZERO, 0, a_dead);
3743 return;
3746 // Need free a do be able to partially restore hl below.
3747 bool pushed_a = false;
3748 if ((aopInReg (to, to_offset, L_IDX) || aopInReg (to, to_offset, H_IDX)) && !a_dead)
3750 _push (PAIR_AF);
3751 pushed_a = true;
3754 _push (PAIR_HL);
3755 if (!pushed_a) // Preserve f
3756 _push (PAIR_AF);
3757 emit2 ("ld hl, !immed%d", spOffset(from->aopu.aop_stk));
3758 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
3759 emit2 ("add hl, sp");
3760 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
3761 if (!pushed_a)
3762 _pop (PAIR_AF);
3763 spillPair (PAIR_HL);
3764 cheapMove (to, to_offset, ASMOP_HL, from_offset, a_dead);
3765 if (aopInReg (to, to_offset, L_IDX))
3766 poppairwithsavedreg (PAIR_HL, H_IDX, A_IDX);
3767 else if (aopInReg (to, to_offset, H_IDX))
3768 poppairwithsavedreg (PAIR_HL, L_IDX, A_IDX);
3769 else
3770 _pop (PAIR_HL);
3772 if (pushed_a)
3773 _pop (PAIR_AF);
3775 return;
3778 const bool from_index = aopInReg (from, from_offset, IYL_IDX) || aopInReg (from, from_offset, IYH_IDX);
3779 const bool to_index = aopInReg (to, to_offset, IYL_IDX) || aopInReg (to, to_offset, IYH_IDX);
3780 const bool index = to_index || from_index;
3782 if (to->type == AOP_REG && from->type == AOP_REG)
3784 if (to->aopu.aop_reg[to_offset] == from->aopu.aop_reg[from_offset])
3785 return;
3787 if (!index ||
3788 // eZ80 can assign between any byte of an index register and any non-hl register.
3789 HAS_IYL_INST && !aopInReg (to, to_offset, L_IDX) && !aopInReg (to, to_offset, H_IDX) && !aopInReg (from, from_offset, L_IDX) && !aopInReg (from, from_offset, H_IDX))
3791 if (!regalloc_dry_run)
3792 aopPut (to, aopGet (from, from_offset, false), to_offset);
3793 ld_cost (to, to_offset, from, from_offset, true);
3794 spillPairReg (to->aopu.aop_reg[to_offset]->name);
3795 return;
3797 #if 0 // Might destroy carry. Would also mess up interrupts on TLCS-90.
3798 if (aopInReg (from, from_offset, IYH_IDX) && !to_index && a_dead)
3800 _push(PAIR_IY);
3801 _pop (PAIR_AF);
3802 cheapMove (to, to_offset, ASMOP_A, 0, true);
3803 return;
3805 #endif
3808 if (from->type != AOP_REG && from->type != AOP_LIT && aopIsLitVal (from, from_offset, 1, 0x00))
3810 cheapMove (to, to_offset, ASMOP_ZERO, 0, a_dead);
3811 return;
3813 else if (HAS_IYL_INST && to_index && (from->type == AOP_LIT || from->type == AOP_IMMD))
3815 if (!regalloc_dry_run)
3816 aopPut (to, aopGet (from, from_offset, false), to_offset);
3817 ld_cost (to, 0, from_offset < from->size ? from : ASMOP_ZERO, from_offset, true);
3818 return;
3820 else if (to_index && HAS_IYL_INST)
3822 if (!a_dead)
3823 _push (PAIR_AF);
3824 cheapMove (ASMOP_A, 0, from, from_offset, true);
3825 if (!regalloc_dry_run)
3826 aopPut (to, "a", to_offset);
3827 ld_cost (to, to_offset, ASMOP_A, 0, true);
3828 spillPairReg (to->aopu.aop_reg[to_offset]->name);
3829 if (!a_dead)
3830 _pop (PAIR_AF);
3831 return;
3834 if (to->type == AOP_REG && from_index && !to_index && - _G.stack.pushed - _G.stack.offset >= -128 && !_G.omitFramePtr)
3836 _push(PAIR_IY);
3837 if (!regalloc_dry_run)
3838 emit2 ("ld %s, %d (ix)", aopGet (to, to_offset, false), - _G.stack.pushed - _G.stack.offset + aopInReg (from, from_offset, IYH_IDX));
3839 cost2 (3, 19, 14, 9, 0, 10, 4, 5);
3840 spillPairReg (to->aopu.aop_reg[to_offset]->name);
3841 _pop(PAIR_IY);
3842 return;
3844 else if (to_index && !from_index && from->type == AOP_REG && - _G.stack.pushed - _G.stack.offset >= -128 && !_G.omitFramePtr)
3846 _push(PAIR_IY);
3847 if (!regalloc_dry_run)
3848 emit2 ("ld %d (ix), %s", - _G.stack.pushed - _G.stack.offset + aopInReg (to, to_offset, IYH_IDX), aopGet (from, from_offset, false));
3849 cost2 (3, 19, 15, 10, 0, 10, 4, 5);
3850 _pop(PAIR_IY);
3851 return;
3854 if (from_index && !to_index && !aopInReg (to, to_offset, L_IDX) && !aopInReg (to, to_offset, H_IDX))
3856 _push (PAIR_IY);
3857 emit2 ("ex (sp), hl");
3858 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3859 cheapMove (to, to_offset, aopInReg (from, from_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, a_dead);
3860 emit2 ("ex (sp), hl");
3861 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3862 _pop (PAIR_IY);
3863 return;
3865 else if (to_index && !from_index && !aopInReg (from, from_offset, L_IDX) && !aopInReg (from, from_offset, H_IDX))
3867 _push (PAIR_IY);
3868 emit2 ("ex (sp), hl");
3869 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3870 cheapMove (aopInReg (to, to_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, from, from_offset, a_dead);
3871 emit2 ("ex (sp), hl");
3872 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3873 _pop (PAIR_IY);
3874 return;
3876 else if (from_index && !to_index)
3878 wassert (aopInReg (to, to_offset, L_IDX) || aopInReg (to, to_offset, H_IDX));
3879 _push (PAIR_IY);
3880 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3881 emit2 ("ex (sp), hl");
3882 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3883 cheapMove (aopInReg (to, to_offset, L_IDX) ? ASMOP_E : ASMOP_D, 0, aopInReg (from, from_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, a_dead);
3884 emit2 ("ex (sp), hl");
3885 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3886 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3887 _pop (PAIR_IY);
3888 return;
3890 else if (to_index && !from_index)
3892 wassert (aopInReg (from, from_offset, L_IDX) || aopInReg (from, from_offset, H_IDX));
3893 _push (PAIR_IY);
3894 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3895 emit2 ("ex (sp), hl");
3896 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3897 cheapMove (aopInReg (to, to_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, aopInReg (from, from_offset, L_IDX) ? ASMOP_E : ASMOP_D, 0, a_dead);
3898 emit2 ("ex (sp), hl");
3899 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3900 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
3901 _pop (PAIR_IY);
3902 return;
3904 else if (to_index && from_index)
3906 _push (PAIR_IY);
3907 emit2 ("ex (sp), hl");
3908 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3909 cheapMove (aopInReg (to, to_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, aopInReg (to, to_offset, IYL_IDX) ? ASMOP_L : ASMOP_H, 0, a_dead);
3910 emit2 ("ex (sp), hl");
3911 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3912 _pop (PAIR_IY);
3913 return;
3916 // Try to push to avoid setting up temporary stack pointer in hl or iy.
3917 if ((to->type == AOP_STK || to->type == AOP_EXSTK) && _G.omitFramePtr &&
3918 (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)))
3920 int fp_offset = to->aopu.aop_stk + to_offset + (to->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3921 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
3923 if (!sp_offset)
3925 emit2 ("inc sp");
3926 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
3927 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"))));
3928 if (aopInReg (from, from_offset, IYH_IDX))
3929 cost2 (2 - IS_TLCS90, 1, 13, 12, 0, 8, 4, 5);
3930 else
3931 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
3932 emit2 ("inc sp");
3933 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
3934 return;
3938 if (from->type == AOP_IY && aopInReg (to, to_offset, A_IDX) && from_offset < from->size)
3940 emit2 ("ld a, (%s+%d)", from->aopu.aop_dir, from_offset);
3941 cost2 (3, 13, 12, 9, 16, 10, 4, 4);
3943 else if (aopInReg (from, from_offset, A_IDX) && to->type == AOP_IY)
3945 wassert (to_offset < to->size);
3946 emit2 ("ld (%s+%d), a", to->aopu.aop_dir, to_offset);
3947 cost2 (3, 13, 13, 10, 16, 10, 4, 4);
3949 else if (!aopInReg (to, to_offset, A_IDX) && !aopInReg (from, from_offset, A_IDX) && // Go through a.
3950 (from->type == AOP_DIR ||
3951 from->type == AOP_SFR || to->type == AOP_SFR ||
3952 (to->type == AOP_HL || to->type == AOP_IY || to->type == AOP_EXSTK || to->type == AOP_STK) && (from->type == AOP_HL || from->type == AOP_IY || from->type == AOP_EXSTK || from->type == AOP_STK) ||
3953 (to->type == AOP_HL || IS_SM83 && to->type == AOP_STK || to->type == AOP_EXSTK) && (aopInReg(from, from_offset, L_IDX) || aopInReg(from, from_offset, H_IDX))) ||
3954 to->type == AOP_PAIRPTR && from->type == AOP_PAIRPTR)
3956 if (!a_dead)
3957 _push (PAIR_AF);
3959 cheapMove (ASMOP_A, 0, from, from_offset, true);
3960 cheapMove (to, to_offset, ASMOP_A, 0, true);
3962 if (!a_dead)
3963 _pop (PAIR_AF);
3965 else
3967 if (!regalloc_dry_run)
3968 aopPut (to, aopGet (from, from_offset, false), to_offset);
3969 if (to->type == AOP_REG)
3970 spillPairReg (to->aopu.aop_reg[to_offset]->name);
3972 ld_cost (to, 0, from_offset < from->size ? from : ASMOP_ZERO, from_offset, true);
3976 static void
3977 commitPair (asmop *aop, PAIR_ID id, const iCode *ic, bool dont_destroy) // Obsolete. Replace uses by genMove or genMove_o.
3979 int fp_offset = aop->aopu.aop_stk + (aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
3980 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
3982 if (getPairId (aop) == id)
3983 return;
3985 /* Stack positions will change, so do not assume this is possible in the cost function. */
3986 if (!regalloc_dry_run && !IS_SM83 && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && !sp_offset
3987 && ((!IS_RAB && id == PAIR_HL) || id == PAIR_IY) && !dont_destroy)
3989 emit2 ("ex (sp), %s", _pairs[id].name);
3990 if (id == PAIR_IY)
3991 cost2 (2, 23, 19, 15, 0, 14, 6, 6);
3992 else
3993 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
3994 spillPair (id);
3996 else if ((IS_RAB || IS_TLCS90) && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && (id == PAIR_HL || id == PAIR_IY) &&
3997 (id == PAIR_HL && abs (fp_offset) <= 127 && aop->type == AOP_STK || abs (sp_offset) <= 127))
3999 if (abs (sp_offset) <= 127)
4001 emit2 ("ld %d (sp), %s", sp_offset, id == PAIR_IY ? "iy" : "hl"); /* Relative to stack pointer. */
4002 cost2 (2 + IS_TLCS90, 0, 0, 11, 0, 12, 0, 0);
4004 else
4006 emit2 ("ld %d (ix), hl", fp_offset); /* Relative to frame pointer. */
4007 cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5, 0);
4010 else if (IS_EZ80_Z80 && aop->type == AOP_STK)
4012 emit2 ("ld %d (ix), %s", fp_offset, _pairs[id].name);
4013 cost (3, 5);
4015 else if (!regalloc_dry_run && (aop->type == AOP_STK || aop->type == AOP_EXSTK) && !sp_offset)
4017 emit2 ("inc sp");
4018 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
4019 emit2 ("inc sp");
4020 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
4021 emit2 ("push %s", _pairs[id].name);
4022 if (id == PAIR_IY)
4023 cost2 (2, 15, 13, 12, 0, 8, 4, 5);
4024 else
4025 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
4028 /* PENDING: Verify this. */
4029 else if (id == PAIR_HL && requiresHL (aop) && (IS_SM83 || IY_RESERVED && aop->type != AOP_HL && aop->type != AOP_IY))
4031 if (!isRegDead (D_IDX, ic))
4032 _push (PAIR_DE);
4033 emit3 (A_LD, ASMOP_A, ASMOP_L);
4034 emit3 (A_LD, ASMOP_D, ASMOP_H);
4035 if (!regalloc_dry_run)
4037 aopPut (aop, "a", 0);
4038 aopPut (aop, "d", 1);
4040 ld_cost (aop, 0, ASMOP_A, 0, true);
4041 ld_cost (aop, 0, ASMOP_D, 0, true);
4042 if (!isRegDead (D_IDX, ic))
4043 _pop (PAIR_DE);
4045 else
4047 /* Special cases */
4048 if ((aop->type == AOP_IY || aop->type == AOP_HL) && !IS_SM83 && aop->size == 2)
4050 if (!regalloc_dry_run)
4051 emit2 ("ld !mems, %s", aopGetLitWordLong (aop, 0, FALSE), _pairs[id].name);
4052 if (id == PAIR_HL)
4053 cost2 (3, 16, 16, 13, 0, 0, 5, 5);
4054 else
4055 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
4057 else
4059 switch (id)
4061 case PAIR_BC:
4062 cheapMove (aop, 0, ASMOP_C, 0, true);
4063 cheapMove (aop, 1, ASMOP_B, 0, true);
4064 break;
4065 case PAIR_DE:
4066 if (!IS_SM83 && aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == L_IDX && aop->aopu.aop_reg[1]->rIdx == H_IDX && !dont_destroy)
4068 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4069 swapPairs (PAIR_DE, PAIR_HL);
4071 else
4073 cheapMove (aop, 0, ASMOP_E, 0, true);
4074 cheapMove (aop, 1, ASMOP_D, 0, true);
4076 break;
4077 case PAIR_HL:
4078 if (aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == H_IDX && aop->aopu.aop_reg[1]->rIdx == L_IDX)
4080 cheapMove (ASMOP_A, 0, ASMOP_L, 0, true);
4081 cheapMove (aop, 1, ASMOP_H, 0, true);
4082 cheapMove (aop, 0, ASMOP_A, 0, true);
4084 else if (aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == H_IDX) // Do not overwrite upper byte.
4086 cheapMove (aop, 1, ASMOP_H, 0, true);
4087 cheapMove (aop, 0, ASMOP_L, 0, true);
4089 else if (!IS_SM83 && aop->type == AOP_REG && aop->aopu.aop_reg[0]->rIdx == E_IDX && aop->aopu.aop_reg[1]->rIdx == D_IDX && !dont_destroy)
4091 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4092 swapPairs (PAIR_DE, PAIR_HL);
4094 else
4096 cheapMove (aop, 0, ASMOP_L, 0, true);
4097 cheapMove (aop, 1, ASMOP_H, 0, true);
4099 break;
4100 case PAIR_IY:
4101 cheapMove (aop, 0, ASMOP_IYL, 0, true);
4102 cheapMove (aop, 1, ASMOP_IYH, 0, true);
4103 break;
4104 default:
4105 wassertl (0, "Unknown pair id in commitPair()");
4106 fprintf (stderr, "pair %s\n", _pairs[id].name);
4112 /*-----------------------------------------------------------------*/
4113 /* genCopyStack - Copy the value - stack to stack only */
4114 /*-----------------------------------------------------------------*/
4115 static void
4116 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)
4118 // Avoid overwriting source. Do not assume stack locations during dry run - they can change later.
4119 int dir = (!regalloc_dry_run && result->aopu.aop_stk + roffset > source->aopu.aop_stk + soffset && result->aopu.aop_stk + roffset < source->aopu.aop_stk + soffset + n) ? -1 : 1;
4121 for (int j = 0; j < n;)
4123 int i = (dir >= 0) ? j : (n - j - 1);
4125 if (assigned[i])
4127 j++;
4128 continue;
4131 if (!aopOnStack (result, roffset + i, 1) || !aopOnStack (source, soffset + i, 1))
4133 j++;
4134 continue;
4137 int source_fp_offset = source->aopu.aop_stk + soffset + i + (source->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
4138 int source_sp_offset = source_fp_offset + _G.stack.pushed + _G.stack.offset;
4139 int result_fp_offset = result->aopu.aop_stk + roffset + i + (result->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
4140 int result_sp_offset = result_fp_offset + _G.stack.pushed + _G.stack.offset;
4142 if (result_fp_offset == source_fp_offset && !regalloc_dry_run) // Stack locations can change, so in dry run do not assume stack coalescing will happen.
4144 assigned[i] = true;
4145 j++;
4146 continue;
4149 bool source_sp = IS_RAB && source_sp_offset <= 255 || IS_TLCS90 && source_sp_offset <= 127;
4150 bool result_sp = IS_RAB && result_sp_offset <= 255 || IS_TLCS90 && result_sp_offset <= 127;
4151 if (i + 1 < n && !assigned[i + 1] && hl_free && (IS_RAB || IS_EZ80_Z80 || IS_TLCS90) && // Todo: For Rabbit, use ld hl n (sp) and ld n(sp), hl when sp_offset is <= 255.
4152 (result->type == AOP_STK && result_fp_offset >= -128 && result_fp_offset <= 127 || result_sp) &&
4153 (source->type == AOP_STK && source_fp_offset >= -128 && source_fp_offset <= 127 || source_sp))
4155 if (!regalloc_dry_run)
4157 if (source_sp)
4158 emit2 ("ld hl, %d (sp)", source_sp_offset);
4159 else
4160 emit2 ("ld hl, %s", aopGet (source, soffset + i, false));
4161 if (result_sp)
4162 emit2 ("ld %d (sp), hl", result_sp_offset);
4163 else
4164 emit2 ("ld %s, hl", aopGet (result, roffset + i, false));
4166 cost2 (6 - 2 * IS_RAB, 0, 0, 22, 0, 21, 10, 0);
4168 spillPair (PAIR_HL);
4170 assigned[i] = true;
4171 assigned[i + 1] = true;
4172 (*size) -= 2;
4173 j += 2;
4174 continue;
4177 if (a_free || really_do_it_now)
4179 if ((requiresHL (result) || requiresHL (source)) && !hl_free)
4180 _push (PAIR_HL);
4181 cheapMove (result, roffset + i, source, soffset + i, a_free);
4182 if ((requiresHL (result) || requiresHL (source)) && !hl_free)
4183 _pop (PAIR_HL);
4184 assigned[i] = true;
4185 (*size)--;
4186 j++;
4187 continue;
4190 j++;
4193 wassertl_bt (*size >= 0, "genCopyStack() copied more than there is to be copied.");
4196 /*-----------------------------------------------------------------*/
4197 /* genCopy - Copy the value from one reg/stk asmop to another */
4198 /*-----------------------------------------------------------------*/
4199 static void
4200 genCopy (asmop *result, int roffset, asmop *source, int soffset, int sizex, bool a_dead, bool hl_dead, bool de_dead)
4202 int regsize, size, n = (sizex < source->size - soffset) ? sizex : (source->size - soffset);
4203 bool assigned[8] = {false, false, false, false, false, false, false, false};
4204 bool a_free, hl_free;
4205 int cached_byte = -1;
4206 bool pushed_a = false;
4208 wassertl_bt (n <= 8, "Invalid size for genCopy().");
4209 wassertl_bt (aopRS (source), "Invalid source type.");
4210 wassertl_bt (aopRS (result), "Invalid result type.");
4212 a_dead |= (result->regs[A_IDX] >= roffset && result->regs[A_IDX] < roffset + sizex);
4213 hl_dead |= (result->regs[L_IDX] >= roffset && result->regs[L_IDX] < roffset + sizex && result->regs[H_IDX] >= roffset && result->regs[H_IDX] < roffset + sizex);
4214 de_dead |= (result->regs[E_IDX] >= roffset && result->regs[E_IDX] < roffset + sizex && result->regs[D_IDX] >= roffset && result->regs[D_IDX] < roffset + sizex);
4216 size = n;
4217 regsize = 0;
4218 for (int i = 0; i < n; i++)
4219 regsize += (source->type == AOP_REG);
4221 // Do nothing for coalesced bytes.
4222 for (int i = 0; i < n; i++)
4223 if (result->type == AOP_REG && source->type == AOP_REG && result->aopu.aop_reg[roffset + i] == source->aopu.aop_reg[soffset + i])
4225 assigned[i] = true;
4226 regsize--;
4227 size--;
4230 // Move everything from registers to the stack.
4231 wassert (source->type != AOP_REG || source->size < 8);
4232 for (int i = 0; i < n && source->type == AOP_REG;)
4234 bool a_free = a_dead && (source->regs[A_IDX] < soffset || assigned[source->regs[A_IDX] - soffset] || i == source->regs[A_IDX] - soffset);
4235 bool hl_free = hl_dead && (source->regs[L_IDX] < soffset || assigned[source->regs[L_IDX] - soffset] || i == source->regs[L_IDX] - soffset) && (source->regs[H_IDX] < soffset || assigned[source->regs[H_IDX] - soffset] || i == source->regs[H_IDX] - soffset);
4236 bool de_free = de_dead && (source->regs[E_IDX] < soffset || assigned[source->regs[E_IDX] - soffset] || i == source->regs[E_IDX] - soffset) && (source->regs[D_IDX] < soffset || assigned[source->regs[D_IDX] - soffset] || i == source->regs[D_IDX] - soffset);
4238 int fp_offset = result->aopu.aop_stk + (result->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) + roffset + i;
4239 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
4241 if (!IS_SM83 && !IS_RAB && !(IS_TLCS90 && optimize.codeSpeed) && // The sm83 doesn't have ex (sp), hl. The Rabbits and tlcs90 have it, but ld 0 (sp), hl is faster. For the Rabbits, they are also the same size.
4242 i + 1 < n && aopOnStack (result, roffset + i, 2) && !sp_offset &&
4243 aopInReg (source, soffset + i, HL_IDX) && hl_dead && // If we knew that iy was dead, we could also use ex (sp), iy here.
4244 !regalloc_dry_run) // Stack positions will change, so do not assume this is possible in the cost function.
4246 emit2 ("ex (sp), hl");
4247 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
4248 spillPair (PAIR_HL);
4249 assigned[i] = true;
4250 assigned[i + 1] = true;
4251 regsize -= 2;
4252 size -= 2;
4253 i += 2;
4255 else if (i + 1 < n && aopOnStack (result, roffset + i, 2) && (abs(fp_offset) <= 127 && !_G.omitFramePtr || IS_RAB && sp_offset <= 255 || IS_TLCS90 && sp_offset <= 127) &&
4256 ((aopInReg (source, soffset + i, HL_IDX) || aopInReg (source, soffset + i, IY_IDX)) && IS_RAB || (getPairId_o (source, soffset + i) != PAIR_INVALID && (IS_EZ80_Z80 || IS_TLCS90))))
4258 bool use_sp = IS_RAB && sp_offset <= 255 || IS_TLCS90 && sp_offset <= 127;
4259 if (!regalloc_dry_run)
4260 emit2 ("ld %d %s, %s", use_sp ? sp_offset : fp_offset, use_sp ? "(sp)" : "(ix)", _pairs[getPairId_o (source, soffset + i)].name);
4261 cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5, 0);
4262 assigned[i] = true;
4263 assigned[i + 1] = true;
4264 regsize -= 2;
4265 size -= 2;
4266 i += 2;
4268 else if (IS_RAB && i + 1 < n && aopOnStack (result, roffset + i, 2) && aopInReg (source, soffset + i, IY_IDX) &&
4269 sp_offset <= 255)
4271 emit2 ("ld %d (sp), iy", sp_offset);
4272 cost2 (3, 0, 0, 13, 0, 0, 0, 0);
4273 assigned[i] = true;
4274 assigned[i + 1] = true;
4275 regsize -= 2;
4276 size -= 2;
4277 i += 2;
4279 else if (i + 1 < n && aopOnStack (result, roffset + i, 2) && getPairId_o (source, soffset + i) != PAIR_INVALID && !sp_offset && !regalloc_dry_run) // Stack positions will change, so do not assume this is possible in the cost function.
4281 bool iy = aopInReg (source, soffset + i, IY_IDX);
4282 emit2 ("inc sp");
4283 emit2 ("inc sp");
4284 emit2 ("push %s", _pairs[getPairId_o (source, soffset + i)].name);
4285 cost2 (3 + iy, 23 + 4 * iy, 19 + 3 * iy, 14 + 2 * iy, 32, 16, 5 + iy, 6 + iy);
4286 assigned[i] = true;
4287 assigned[i + 1] = true;
4288 regsize -= 2;
4289 size -= 2;
4290 i += 2;
4292 else if (IS_RAB && i + 1 < n && aopOnStack (result, roffset + i, 2) && aopInReg (source, soffset + i, DE_IDX) &&
4293 (sp_offset <= 255 || abs(fp_offset) <= 127 && !_G.omitFramePtr))
4295 bool use_sp = (sp_offset <= 255);
4296 emit2 ("ex de, hl");
4297 if (!regalloc_dry_run)
4298 emit2 ("ld %d %s, hl", use_sp ? sp_offset : fp_offset, use_sp ? "(sp)" : "(ix)");
4299 cost2 (3, 0, 0, 13, 0, 0, 0, 0);
4300 if (!de_dead || !hl_dead || source->regs[L_IDX] >= 0 && !assigned[source->regs[L_IDX]] || source->regs[H_IDX] >= 0 && !assigned[source->regs[H_IDX]])
4301 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4302 spillPair (PAIR_HL);
4303 assigned[i] = true;
4304 assigned[i + 1] = true;
4305 regsize -= 2;
4306 size -= 2;
4307 i += 2;
4309 else if (!IS_SM83 && i + 1 < n && aopOnStack (result, roffset + i, 2) && requiresHL (result) &&
4310 aopInReg (source, soffset + i, HL_IDX) && hl_free)
4312 if (!de_free)
4313 _push (PAIR_DE);
4314 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4315 spillPair (PAIR_HL);
4316 genCopy (result, roffset + i, ASMOP_DE, 0, 2, a_free, true, true);
4317 if (!de_free)
4318 _pop (PAIR_DE);
4319 assigned[i] = true;
4320 assigned[i + 1] = true;
4321 regsize -= 2;
4322 size -= 2;
4323 i += 2;
4325 else if (aopOnStack (result, roffset + i, 1) && requiresHL (result) && !hl_free)
4327 _push(PAIR_HL);
4328 cheapMove (result, roffset + i, source, soffset + i, a_free);
4329 _pop(PAIR_HL);
4330 assigned[i] = true;
4331 regsize--;
4332 size--;
4333 i++;
4335 else if (aopRS (source) && !aopOnStack (source, soffset + i, 1) && aopOnStack (result, roffset + i, 1))
4337 cheapMove (result, roffset + i, source, soffset + i, a_free);
4338 assigned[i] = true;
4339 regsize--;
4340 size--;
4341 i++;
4343 else // This byte is not a register-to-stack copy.
4344 i++;
4347 // Copy (stack-to-stack) what we can with whatever free regs we have.
4348 a_free = a_dead;
4349 hl_free = hl_dead;
4350 for (int i = 0; i < n; i++)
4352 asmop *operand;
4353 int offset;
4355 if (!assigned[i])
4357 operand = source;
4358 offset = soffset + i;
4360 else
4362 operand = result;
4363 offset = roffset + i;
4366 if (aopInReg (operand, offset, A_IDX))
4367 a_free = false;
4368 else if (aopInReg (operand, offset, L_IDX) || aopInReg (operand, offset, H_IDX))
4369 hl_free = false;
4371 genCopyStack (result, roffset, source, soffset, n, assigned, &size, a_free, hl_free, false);
4373 // Now do the register shuffling.
4375 // Try to use:
4376 // Rabbits: ld hl, iy; ld iy, hl
4377 // TLCS-90 ld rr, rr
4378 // eZ80 lea rr, iy.
4379 // All: push rr / pop iy
4380 // All: push iy / pop rr
4381 for (int i = 0; i + 1 < n; i++)
4383 if (assigned[i] || assigned[i + 1])
4384 continue;
4386 for (int j = 0; j + 1 < n; j++)
4388 if (!assigned[j] && i != j && i + 1 != j && !aopOnStack(result, roffset + i, 2) && !aopOnStack(source, soffset + i, 1) &&
4389 (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]))
4390 goto skip_byte_push_iy; // We can't write this one without overwriting the source.
4393 if (IS_RAB && (getPairId_o (result, roffset + i) == PAIR_HL || getPairId_o (result, roffset + i) == PAIR_IY) && (getPairId_o (source, soffset + i) == PAIR_HL || getPairId_o (source, soffset + i) == PAIR_IY))
4395 emit2 ("ld %s, %s", _pairs[getPairId_o (result, roffset + i)].name, _pairs[getPairId_o (source, soffset + i)].name);
4396 cost (2, 4);
4397 spillPair (getPairId_o (result, roffset + i));
4399 else if (IS_TLCS90 && getPairId_o (result, roffset + i) != PAIR_INVALID && getPairId_o (source, soffset + i) != PAIR_INVALID)
4401 emit2 ("ld %s, %s", _pairs[getPairId_o (result, roffset + i)].name, _pairs[getPairId_o (source, soffset + i)].name);
4402 bool hl = (aopInReg (result, roffset + i, HL_IDX) ^ aopInReg (source, soffset + i, HL_IDX));
4403 cost (2 - hl, 6 - 2 * hl);
4404 spillPair (getPairId_o (result, roffset + i));
4406 else if (IS_EZ80_Z80 && getPairId_o (result, roffset + i) != PAIR_INVALID && aopInReg (source, soffset + i, IY_IDX))
4408 emit2 ("lea %s, iy, !zero", _pairs[getPairId_o (result, roffset + i)].name);
4409 cost (3, 3);
4410 spillPair (getPairId_o (result, roffset + i));
4412 else if (aopInReg (result, roffset + i, IY_IDX) && getPairId_o (source, soffset + i) != PAIR_INVALID ||
4413 getPairId_o (result, roffset + i) != PAIR_INVALID && aopInReg (source, soffset + i, IY_IDX))
4415 _push (getPairId_o (source, soffset + i));
4416 _pop (getPairId_o (result, roffset + i));
4418 else
4419 continue;
4421 regsize -= 2;
4422 size -= 2;
4423 assigned[i] = true;
4424 assigned[i + 1] = true;
4426 skip_byte_push_iy:
4430 if (!IS_SM83)
4432 int ex[4] = {-2, -2, -2, -2}; // Swapped bytes
4433 bool no = false; // Still needed byte would be overwritten
4435 // Find L and check that it is exchanged with E, find H and check that it is exchanged with D.
4436 for (int i = 0; i < n; i++)
4438 if (assigned[i] &&
4439 (aopInReg (result, roffset + i, E_IDX) || aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, D_IDX) || aopInReg (result, roffset + i, H_IDX)))
4440 no = true;
4442 if (!assigned[i] && aopInReg (source, soffset + i, E_IDX))
4443 if (aopInReg (result, roffset + i, L_IDX))
4444 ex[0] = i;
4445 else
4446 no = true;
4447 if (!assigned[i] && aopInReg (source, soffset + i, L_IDX))
4448 if (aopInReg (result, roffset + i, E_IDX))
4449 ex[1] = i;
4450 else
4451 no = true;
4452 if (!assigned[i] && aopInReg (source, soffset + i, D_IDX))
4453 if (aopInReg (result, roffset + i, H_IDX))
4454 ex[2] = i;
4455 else
4456 no = true;
4457 if (!assigned[i] && aopInReg (source, soffset + i, H_IDX))
4458 if (aopInReg (result, roffset + i, D_IDX))
4459 ex[3] = i;
4460 else
4461 no = true;
4464 int exsum = (ex[0] >= 0) + (ex[1] >= 0) + (ex[2] >= 0) + (ex[3] >= 0);
4466 if (!no && exsum >= 2 && hl_dead && de_dead)
4468 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4469 swapPairs (PAIR_DE, PAIR_HL);
4470 if(ex[0] >= 0)
4471 assigned[ex[0]] = TRUE;
4472 if(ex[1] >= 0)
4473 assigned[ex[1]] = TRUE;
4474 if(ex[2] >= 0)
4475 assigned[ex[2]] = TRUE;
4476 if(ex[3] >= 0)
4477 assigned[ex[3]] = TRUE;
4478 regsize -= exsum;
4479 size -= exsum;
4483 while (regsize && result->type == AOP_REG && source->type == AOP_REG)
4485 int i;
4487 // Find lowest byte that can be assigned and needs to be assigned.
4488 for (i = 0; i < n; i++)
4490 if (assigned[i])
4491 continue;
4493 for (int j = 0; j < n; j++)
4495 if (!assigned[j] && i != j && result->aopu.aop_reg[roffset + i] == source->aopu.aop_reg[soffset + j])
4496 goto skip_byte; // We can't write this one without overwriting the source.
4499 break; // Found byte that can be written safely.
4501 skip_byte:
4505 if (i < n)
4507 cheapMove (result, roffset + i, source, soffset + i, false); // We can safely assign a byte.
4508 regsize--;
4509 size--;
4510 assigned[i] = true;
4511 if (aopInReg (result, roffset + i, A_IDX))
4512 a_free = false;
4513 continue;
4516 // No byte can be assigned safely (i.e. the assignment is a permutation). Cache one in the accumulator.
4518 if (cached_byte != -1)
4520 // Already one cached. Can happen when the assignment is a permutation consisting of multiple cycles.
4521 cheapMove (result, roffset + cached_byte, ASMOP_A, 0, true);
4522 cached_byte = -1;
4523 continue;
4526 for (i = 0; i < n; i++)
4527 if (!assigned[i])
4528 break;
4530 wassertl_bt (i != n, "genCopy error: Trying to cache non-existent byte in accumulator.");
4531 if (!a_free && !pushed_a)
4533 _push (PAIR_AF);
4534 pushed_a = TRUE;
4536 cheapMove (ASMOP_A, 0, source, soffset + i, true);
4537 regsize--;
4538 size--;
4539 assigned[i] = TRUE;
4540 cached_byte = i;
4543 // Copy (stack-to-stack) what we can with whatever free regs we have now.
4544 a_free = a_dead;
4545 hl_free = hl_dead;
4546 for (int i = 0; i < n; i++)
4548 if (!assigned[i])
4549 continue;
4550 if (aopInReg (result, roffset + i, A_IDX))
4551 a_free = false;
4552 else if (aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, H_IDX))
4553 hl_free = false;
4555 genCopyStack (result, roffset, source, soffset, n, assigned, &size, a_free, hl_free, false);
4557 // Take de from stack first on Rabbit, while hl is still free, so we can do with just one ex de, hl.
4558 if (IS_RAB && hl_free &&
4559 result->regs[E_IDX] > roffset && result->regs[E_IDX] < roffset + n && !assigned[result->regs[E_IDX] - roffset] &&
4560 result->regs[D_IDX] > roffset && result->regs[D_IDX] < roffset + n && !assigned[result->regs[D_IDX] - roffset] &&
4561 result->regs[E_IDX] + 1 == result->regs[D_IDX])
4563 int i = result->regs[E_IDX] - roffset;
4564 const int fp_offset = source->aopu.aop_stk + soffset + i + (source->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
4565 const int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
4566 if (sp_offset <= 255 || fp_offset <= 127)
4568 if (!regalloc_dry_run)
4569 if (sp_offset <= 255)
4571 emit2 ("ld hl, %d (sp)", sp_offset);
4573 else
4575 emit2 ("ld hl, %s", aopGet (source, soffset + i, false));
4577 cost (2, 9);
4578 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4579 spillPair (PAIR_HL);
4580 spillPair (PAIR_DE);
4581 assigned[i] = true;
4582 assigned[i + 1] = true;
4583 size -= 2;
4584 i += 2;
4588 // Last, move everything else from stack to registers.
4589 wassert (result->type != AOP_REG || result->size < 8);
4590 for (int i = 0; i < n && result->type == AOP_REG;)
4592 const int fp_offset = source->aopu.aop_stk + soffset + i + (source->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
4593 const int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
4595 bool a_free = a_dead && (result->regs[A_IDX] < roffset || !assigned[result->regs[A_IDX] - roffset]);
4596 const bool hl_free = hl_dead && (result->regs[L_IDX] < roffset || !assigned[result->regs[L_IDX] - roffset]) && (result->regs[H_IDX] < roffset || !assigned[result->regs[H_IDX] - roffset]);
4597 const bool e_free = de_dead && (result->regs[E_IDX] < roffset || !assigned[result->regs[E_IDX] - roffset]);
4598 const bool d_free = de_dead && (result->regs[D_IDX] < roffset || !assigned[result->regs[D_IDX] - roffset]);
4599 const bool de_free = e_free && d_free;
4601 if (assigned[i])
4603 i++;
4604 continue;
4606 else if (i + 1 < n && !assigned[i + 1] && (source->type == AOP_STK || source->type == AOP_EXSTK) &&
4607 (IS_RAB && sp_offset <= 255 || IS_TLCS90 && sp_offset <= 127) &&
4608 (aopInReg (result, roffset + i, HL_IDX) || aopInReg (result, roffset + i, IY_IDX)))
4610 if (!regalloc_dry_run)
4611 emit2 ("ld %s, %d (sp)", _pairs[getPairId_o (result, roffset + i)].name, sp_offset);
4612 spillPair (getPairId_o (result, roffset + i));
4613 cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 0, 0);
4614 assigned[i] = true;
4615 assigned[i + 1] = true;
4616 size -= 2;
4617 i += 2;
4619 else if (i + 1 < n && !assigned[i + 1] && source->type == AOP_STK &&
4620 (aopInReg (result, roffset + i, HL_IDX) && IS_RAB ||
4621 (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)))
4623 if (!regalloc_dry_run)
4624 emit2 ("ld %s, %s", _pairs[getPairId_o (result, roffset + i)].name, aopGet (source, soffset + i, false));
4625 spillPair (getPairId_o (result, roffset + i));
4626 cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5, 0);
4627 assigned[i] = true;
4628 assigned[i + 1] = true;
4629 size -= 2;
4630 i += 2;
4632 else if (i + 1 < n && !assigned[i + 1] && (source->type == AOP_STK || source->type == AOP_EXSTK) &&
4633 !sp_offset && getPairId_o (result, roffset + i) != PAIR_INVALID &&
4634 !regalloc_dry_run) // Stack locations might change.
4636 PAIR_ID pair = getPairId_o (result, roffset + i);
4637 _pop (pair);
4638 _push (pair);
4639 assigned[i] = true;
4640 assigned[i + 1] = true;
4641 size -= 2;
4642 i += 2;
4644 else if (i + 1 < n && !assigned[i + 1] && (source->type == AOP_STK || source->type == AOP_EXSTK) &&
4645 sp_offset == 2 && getPairId_o (result, roffset + i) != PAIR_INVALID &&
4646 (getPairId_o (result, roffset + i) != PAIR_HL && hl_free || getPairId_o (result, roffset + i) != PAIR_DE && de_free) &&
4647 (!regalloc_dry_run || source->aopu.aop_stk > 0) && // Stack locations might change, unless its a parameter.
4648 !(IS_RAB && aopInReg (result, roffset + i, DE_IDX)) && // For de, Rabbit can do it faster at same code size using ex twice
4649 (!IS_SM83 || optimize.codeSize) // SM83 can do it faster (worst case 2B bigger, but 1B smaller if lucky -> hl reuse)
4650 && !optimize.codeSpeed) // A bit slower (42 vs 38 cycles on Z80 and Z80N), so don't do it when optimizing for speed.
4652 PAIR_ID pair = getPairId_o (result, roffset + i);
4653 PAIR_ID extrapair = (getPairId_o (result, roffset + i) != PAIR_HL && hl_free) ? PAIR_HL : PAIR_DE; // If we knew it is dead, we could use bc as extrapair here, too.
4654 _pop (extrapair);
4655 _pop (pair);
4656 _push (pair);
4657 _push (extrapair);
4658 spillPair (extrapair);
4659 assigned[i] = true;
4660 assigned[i + 1] = true;
4661 size -= 2;
4662 i += 2;
4664 else if (i + 1 < n && !assigned[i + 1] &&
4665 (source->type == AOP_STK && fp_offset <= 127 || sp_offset <= 255) &&
4666 (aopInReg (result, roffset + i, DE_IDX) || result->type == AOP_REG && result->regs[L_IDX] < i && result->regs[IYL_IDX] < i && result->regs[H_IDX] < i && result->regs[IYH_IDX] < i && hl_free) &&
4667 IS_RAB)
4669 if (!hl_free)
4670 emit2 ("ex de, hl");
4671 if (!regalloc_dry_run)
4672 if (sp_offset <= 255)
4673 emit2 ("ld hl, %d (sp)", sp_offset);
4674 else
4675 emit2 ("ld hl, %s", aopGet (source, soffset + i, false));
4676 cost2 (2 + !hl_free, 0, 0, 11 + !hl_free * 2, 0, 0, 0, 0);
4677 spillPair (PAIR_HL);
4678 if (aopInReg (result, roffset + i, DE_IDX))
4679 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4680 else
4682 wassert (hl_free);
4683 emit3_o (A_LD, result, roffset + i, ASMOP_L, 0);
4684 emit3_o (A_LD, result, roffset + i + 1, ASMOP_H, 0);
4686 assigned[i] = true;
4687 assigned[i + 1] = true;
4688 size -= 2;
4689 i += 2;
4691 else if (i + 1 < n && !assigned[i + 1] && (source->type == AOP_STK || source->type == AOP_EXSTK) && requiresHL (source) &&
4692 (aopInReg (result, roffset + i, HL_IDX) || aopInReg (result, roffset + i, H_IDX) && aopInReg (result, roffset + i + 1, L_IDX))) // Stack access might go through hl.
4694 bool a_pushed = false;
4695 if (!a_free && !e_free && !d_free)
4697 _push (PAIR_AF);
4698 a_pushed = true;
4699 a_free = true;
4701 asmop *tmpaop = a_free ? ASMOP_A : e_free ? ASMOP_E : ASMOP_D;
4702 cheapMove (tmpaop, 0, source, soffset + i, true);
4703 cheapMove (result, roffset + i + 1, source, soffset + i + 1, false);
4704 cheapMove (result, roffset + i, tmpaop, 0, true);
4705 if (a_pushed)
4706 _pop (PAIR_AF);
4707 assigned[i] = true;
4708 assigned[i + 1] = true;
4709 size -= 2;
4710 i += 2;
4712 else if (aopRS (result) && aopOnStack (source, soffset + i, 1) && !aopOnStack (result, roffset + i, 1))
4714 if (requiresHL (source) && !hl_free && (aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, H_IDX)))
4716 if (!a_free)
4717 _push (PAIR_AF);
4718 _push (PAIR_HL);
4719 cheapMove (ASMOP_A, 0, source, soffset + i, true);
4720 _pop (PAIR_HL);
4721 cheapMove (result, roffset + i, ASMOP_A, 0, true);
4722 if (!a_free)
4723 _pop (PAIR_AF);
4725 else
4727 if (requiresHL (source) && !hl_free)
4728 _push (PAIR_HL);
4729 cheapMove (result, roffset + i, source, soffset + i, a_free);
4730 if (requiresHL (source) && source->type != AOP_REG && !hl_free)
4731 _pop (PAIR_HL);
4733 assigned[i] = true;
4734 size--;
4735 i++;
4737 else // This byte is not a register-to-stack copy.
4738 i++;
4741 // Free a reg to copy (stack-to-stack) whatever is left.
4742 if (size)
4744 a_free = a_dead && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= roffset + source->size);
4745 hl_free = hl_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);
4746 if (!a_free)
4747 _push (PAIR_AF);
4748 genCopyStack (result, roffset, source, soffset, n, assigned, &size, true, hl_free, true);
4749 if (!a_free)
4750 _pop (PAIR_AF);
4753 wassertl_bt (size >= 0, "genCopy() copied more than there is to be copied.");
4755 a_free = a_dead && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= roffset + source->size);
4757 // Place leading zeroes.
4759 // todo
4761 if (cached_byte != -1)
4762 cheapMove (result, roffset + cached_byte, ASMOP_A, 0, true);
4764 if (pushed_a)
4765 _pop (PAIR_AF);
4768 /*-----------------------------------------------------------------*/
4769 /* genMove_o - Copy part of one asmop to another */
4770 /*-----------------------------------------------------------------*/
4771 static void
4772 genMove_o (asmop *result, int roffset, asmop *source, int soffset, int size, bool a_dead_global, bool hl_dead_global, bool de_dead_global, bool iy_dead_global, bool f_dead)
4774 wassert (result);
4775 wassert (result->size >= roffset + size);
4776 emitDebug ("; genMove_o size %d result type %d source type %d hl_dead %d", size, result->type, source->type, hl_dead_global);
4778 a_dead_global |= result->type == AOP_REG && result->regs[A_IDX] >= roffset && result->regs[A_IDX] < roffset + size;
4779 hl_dead_global |= result->type == AOP_REG && result->regs[L_IDX] >= roffset && result->regs[L_IDX] < roffset + size && result->regs[H_IDX] >= roffset && result->regs[H_IDX] < roffset + size;
4780 de_dead_global |= result->type == AOP_REG && result->regs[E_IDX] >= roffset && result->regs[E_IDX] < roffset + size && result->regs[D_IDX] >= roffset && result->regs[D_IDX] < roffset + size;
4781 iy_dead_global |= result->type == AOP_REG && result->regs[IYL_IDX] >= roffset && result->regs[IYL_IDX] < roffset + size && result->regs[IYH_IDX] >= roffset && result->regs[IYH_IDX] < roffset + size;
4782 bool bc_dead_global = result->type == AOP_REG && result->regs[C_IDX] >= roffset && result->regs[C_IDX] < roffset + size && result->regs[B_IDX] >= roffset && result->regs[B_IDX] < roffset + size;
4784 if (aopSame (result, roffset, source, soffset, size))
4785 return;
4787 if ((result->type == AOP_REG || result->type == AOP_STK || result->type == AOP_EXSTK) && (source->type == AOP_REG || source->type == AOP_STK || source->type == AOP_EXSTK))
4789 int csize = size > source->size - soffset ? source->size - soffset : size;
4790 genCopy (result, roffset, source, soffset, csize, a_dead_global, hl_dead_global, de_dead_global);
4791 roffset += csize;
4792 size -= csize;
4793 bool a_dead = a_dead_global && result->regs[A_IDX] < roffset;
4794 bool hl_dead = hl_dead_global && result->regs[H_IDX] < roffset && result->regs[L_IDX] < roffset;
4795 bool de_dead = de_dead_global && result->regs[D_IDX] < roffset && result->regs[E_IDX] < roffset;
4796 bool iy_dead = iy_dead_global && result->regs[IYH_IDX] < roffset && result->regs[IYL_IDX] < roffset;
4797 genMove_o (result, roffset, ASMOP_ZERO, 0, size, a_dead, hl_dead, de_dead, iy_dead, f_dead);
4798 return;
4801 bool zeroed_a = false;
4802 long value_hl = -1;
4804 for (int i = 0; i < size;)
4806 bool a_dead = a_dead_global && source->regs[A_IDX] <= soffset + i && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= roffset + i);
4807 bool hl_dead = hl_dead_global && source->regs[L_IDX] <= soffset + i && source->regs[H_IDX] <= soffset + i && (result->regs[L_IDX] < 0 || result->regs[L_IDX] >= roffset + i) && (result->regs[H_IDX] < 0 || result->regs[H_IDX] >= roffset + i);
4808 bool de_dead = de_dead_global && source->regs[E_IDX] <= soffset + i && source->regs[D_IDX] <= soffset + i && (result->regs[E_IDX] < 0 || result->regs[E_IDX] >= roffset + i) && (result->regs[D_IDX] < 0 || result->regs[D_IDX] >= roffset + i);
4809 bool iy_dead = iy_dead_global && source->regs[IYL_IDX] <= soffset + i && source->regs[IYH_IDX] <= soffset + i && (result->regs[IYL_IDX] < 0 || result->regs[IYL_IDX] >= roffset + i) && (result->regs[IYH_IDX] < 0 || result->regs[IYH_IDX] >= roffset + i);
4810 bool bc_dead = bc_dead_global && source->regs[C_IDX] <= soffset + i && source->regs[B_IDX] <= soffset + i && (result->regs[C_IDX] < 0 || result->regs[C_IDX] >= roffset + i) && (result->regs[B_IDX] < 0 || result->regs[B_IDX] >= roffset + i);
4812 if (source->type == AOP_STL && (soffset + i) >= 2)
4814 genMove_o (result, roffset + i, ASMOP_ZERO, 0, size - i, a_dead, hl_dead, false, iy_dead, f_dead);
4815 return;
4817 else if ((IS_TLCS90 || IS_EZ80_Z80) && source->type == AOP_STL && !(soffset + i) && getPairId_o(result, roffset) != PAIR_INVALID &&
4818 !_G.omitFramePtr && abs(fpOffset (source->aopu.aop_stk)) <= 127)
4820 emit2 (IS_TLCS90 ? "lda %s, ix, !immed%d" : "lea %s, ix, !immed%d", _pairs[getPairId_o(result, roffset)].name, fpOffset (source->aopu.aop_stk));
4821 spillPair (getPairId_o(result, roffset));
4822 cost (3, IS_TLCS90 ? 10 : 3);
4823 i += 2;
4824 continue;
4826 else if (source->type == AOP_STL && !(soffset + i) && getPairId_o(result, roffset) == PAIR_IY)
4828 if (!f_dead)
4829 _push (PAIR_AF);
4830 emit2 ("ld iy, !immed%d", spOffset (source->aopu.aop_stk));
4831 emit2 ("add iy, sp");
4832 cost2 (6 - IS_TLCS90, 29, 22, 12, 0, 14, 6, 6);
4833 if (!f_dead)
4834 _pop (PAIR_AF);
4835 spillPair (PAIR_IY);
4836 i += 2;
4837 continue;
4839 else if (!IS_SM83 && source->type == AOP_STL && !(soffset + i) && size == 2 && getPairId_o(result, roffset) == PAIR_DE) // For result in de, we don't need hl dead.
4841 if (!hl_dead)
4842 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4843 else
4844 spillPair (PAIR_HL);
4845 if (!f_dead)
4846 _push (PAIR_AF);
4847 emit2 ("ld hl, !immed%d", spOffset (source->aopu.aop_stk));
4848 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
4849 emit2 ("add hl, sp");
4850 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
4851 if (!f_dead)
4852 _pop (PAIR_AF);
4853 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
4854 spillPair (PAIR_DE);
4855 i += 2;
4856 continue;
4858 else if (source->type == AOP_STL)
4860 if (!hl_dead && (result->regs[L_IDX] > roffset || result->regs[H_IDX] > roffset))
4861 UNIMPLEMENTED;
4862 if (!hl_dead)
4863 _push (PAIR_HL);
4864 if (i + soffset > 1)
4865 UNIMPLEMENTED;
4866 if (!f_dead)
4867 _push (PAIR_AF);
4868 emit2 ("ld hl, !immed%d", spOffset (source->aopu.aop_stk));
4869 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
4870 emit2 ("add hl, sp");
4871 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
4872 if (!f_dead)
4873 _pop (PAIR_AF);
4874 spillPair (PAIR_HL);
4875 genMove_o (result, roffset + i, ASMOP_HL, soffset + i, size, a_dead, true, de_dead_global, iy_dead, f_dead);
4876 if (!hl_dead)
4877 _pop (PAIR_HL);
4878 i += 2;
4879 continue;
4882 if ((IS_EZ80_Z80 || IS_RAB || IS_TLCS90) && i + 1 < size && result->type == AOP_STK &&
4883 source->type == AOP_LIT && (value_hl >= 0 && aopIsLitVal (source, soffset + i, 2, value_hl) || hl_dead))
4885 if (value_hl < 0 || !aopIsLitVal (source, soffset + i, 2, value_hl))
4886 fetchLitPair (PAIR_HL, source, soffset + i, f_dead, false);
4887 if (!regalloc_dry_run)
4888 emit2 ("ld %s, hl", aopGet (result, roffset + i, false));
4889 cost2 (3 - IS_RAB, 0, 0, 11, 0, 12, 5, 0);
4890 value_hl = ullFromVal (source->aopu.aop_lit) >> ((soffset + i) * 8) & 0xffff;
4891 i += 2;
4892 continue;
4894 else if (i + 1 < size && IS_SM83 && result->type != AOP_REG && requiresHL (result) && source->type == AOP_REG && requiresHL (source) && // word through de is cheaper than direct byte-by-byte, since it requires fewer updates of hl.
4895 de_dead_global && source->regs[E_IDX] <= i + 1 && source->regs[D_IDX] <= i + 1 &&
4896 hl_dead_global && source->regs[L_IDX] <= i + 1 && source->regs[H_IDX] <= i + 1)
4898 cheapMove (ASMOP_E, 0, source, i, a_dead);
4899 cheapMove (ASMOP_D, 0, source, i + 1, a_dead);
4900 cheapMove (result, i, ASMOP_E, 0, a_dead);
4901 cheapMove (result, i + 1, ASMOP_D, 0, a_dead);
4902 i += 2;
4903 continue;
4905 else if (!IS_SM83 && i + 1 < size && getPairId_o(source, soffset + i) != PAIR_INVALID &&
4906 (result->type == AOP_IY || result->type == AOP_DIR || result->type == AOP_HL && (getPairId_o(source, soffset + i) == PAIR_HL || !hl_dead)))
4908 emit2 ("ld !mems, %s", aopGetLitWordLong (result, roffset + i, false), _pairs[getPairId_o(source, soffset + i)].name);
4909 if (getPairId_o(source, soffset + i) == PAIR_HL)
4910 cost2 (3, 16, 16, 13, 0, 0, 5, 5);
4911 else
4912 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
4913 i += 2;
4914 continue;
4916 else if (!IS_SM83 && i + 1 < size && soffset + i + 1 < source->size && getPairId_o(result, roffset + i) != PAIR_INVALID &&
4917 (source->type == AOP_IY || source->type == AOP_DIR || source->type == AOP_HL && (getPairId_o(result, roffset + i) == PAIR_HL || !hl_dead)))
4919 emit2 ("ld %s, !mems", _pairs[getPairId_o(result, roffset + i)].name, aopGetLitWordLong (source, soffset + i, false));
4920 if (getPairId_o(result, roffset + i) == PAIR_HL)
4921 cost2 (3, 16, 15, 11, 0, 12, 5, 5);
4922 else
4923 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
4924 spillPair (getPairId_o(result, roffset + i));
4925 i += 2;
4926 continue;
4928 else if (i + 1 < size && getPairId_o(result, roffset + i) != PAIR_INVALID &&
4929 (source->type == AOP_LIT && !(aopIsLitVal (source, soffset + i, 2, 0x0000) && zeroed_a) || source->type == AOP_IMMD))
4931 fetchLitPair (getPairId_o(result, roffset + i), source, soffset + i, f_dead, false);
4932 i += 2;
4933 continue;
4935 else if (!IS_SM83 && i + 1 < size &&
4936 (result->type == AOP_IY || result->type == AOP_DIR || result->type == AOP_HL) &&
4937 source->type == AOP_IMMD && hl_dead)
4939 genMove_o (ASMOP_HL, 0, source, soffset + i, 2, a_dead, true, false, iy_dead, f_dead);
4940 genMove_o (result, roffset + i, ASMOP_HL, 0, 2, a_dead, true, false, iy_dead, f_dead);
4941 i += 2;
4942 continue;
4945 // 16-bit load into register might be cheaper than 8-bit, if the latter has to go through a. For bc and de it is only worth it if a would have to be saved.
4946 if ((optimize.allow_unsafe_read || i + 1 == size && soffset + i + 1 <= source->size) && !IS_SM83 && !IS_TLCS90 && result->type == AOP_REG && !aopInReg (result, roffset + i, A_IDX) &&
4947 (i + 1 == size || soffset + i + 1 >= source->size) && (source->type == AOP_HL && fetchLitPair (PAIR_HL, source, soffset + i, f_dead, true) || source->type == AOP_IY))
4949 bool upper = aopInReg (result, roffset + i, B_IDX) || aopInReg (result, roffset + i, D_IDX) || aopInReg (result, roffset + i, H_IDX) || aopInReg (result, roffset + i, IYH_IDX);
4950 PAIR_ID pair = PAIR_INVALID;
4951 if ((aopInReg (result, roffset + i, C_IDX) || aopInReg (result, roffset + i, B_IDX)) && bc_dead && !a_dead)
4952 pair = PAIR_BC;
4953 else if ((aopInReg (result, roffset + i, E_IDX) || aopInReg (result, roffset + i, D_IDX)) && de_dead && !a_dead)
4954 pair = PAIR_DE;
4955 else if ((aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, H_IDX)) && hl_dead)
4956 pair = PAIR_HL;
4957 else if ((aopInReg (result, roffset + i, IYL_IDX) || aopInReg (result, roffset + i, IYH_IDX)) && iy_dead)
4958 pair = PAIR_IY;
4960 if (pair != PAIR_INVALID && soffset + i - upper >= 0 && (optimize.allow_unsafe_read || upper || soffset + i + 1 < source->size))
4962 emit2 ("ld %s, !mems", _pairs[pair].name, aopGetLitWordLong (source, soffset + i - upper, false));
4963 if (pair == PAIR_HL)
4964 cost2 (3, 16, 15, 11, 0, 12, 5, 5);
4965 else
4966 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
4967 i++;
4968 spillPair (pair);
4969 continue;
4973 // Cache a copy of zero in a.
4974 if (f_dead && !zeroed_a && a_dead && source->regs[A_IDX] <= i &&
4975 (size > 1 && result->type != AOP_REG && aopIsLitVal (source, soffset + i, 2, 0x0000) ||
4976 size == 1 && (result->type == AOP_HL && fetchLitPair (PAIR_HL, result, roffset + i, f_dead, true) || result->type == AOP_IY && fetchLitPair (PAIR_IY, result, roffset + i, f_dead, true)) && aopIsLitVal (source, soffset + i, 1, 0x00)))
4978 emit3 (A_XOR, ASMOP_A, ASMOP_A);
4979 zeroed_a = true;
4982 if (result->type == AOP_HL && a_dead_global && (!hl_dead_global || source->regs[L_IDX] >= i || source->regs[H_IDX] >= i) && source->regs[A_IDX] <= i)
4984 if (source->type == AOP_HL)
4986 emit2 ("ld a, !mems", aopGetLitWordLong (source, soffset + i, false));
4987 cost2 (3, 13, 12, 9, 16, 10, 4, 4);
4989 else if (!aopIsLitVal (source, soffset + i, 1, 0x00) || !zeroed_a)
4991 cheapMove (ASMOP_A, 0, source, soffset + i, true);
4992 zeroed_a = aopIsLitVal (source, soffset + i, 1, 0x00);
4994 emit2 ("ld !mems, a", aopGetLitWordLong (result, roffset + i, FALSE));
4995 cost2 (3, 13, 13, 10, 16, 10, 4, 4);
4997 else if (aopIsLitVal (source, soffset + i, 1, 0x00) && zeroed_a)
4999 if (requiresHL (result) && result->type != AOP_REG && !hl_dead)
5000 _push (PAIR_HL);
5001 cheapMove (result, roffset + i, ASMOP_A, 0, false);
5002 if (requiresHL (result) && result->type != AOP_REG && !hl_dead)
5003 _pop (PAIR_HL);
5005 else if (aopIsLitVal (source, soffset + i, 1, 0x00) && aopInReg (result, roffset + i, A_IDX) && f_dead)
5007 emit3 (A_XOR, ASMOP_A, ASMOP_A);
5008 zeroed_a = true;
5010 else
5012 bool pushed_hl = false;
5013 bool via_a = false;
5014 bool premoved_a = false;
5016 if (!i && a_dead && // Avoid setting up hl or iy for a single byte.
5017 (source->type == AOP_HL && fetchLitPair (PAIR_HL, source, soffset + i, f_dead, true) || source->type == AOP_IY && fetchLitPair (PAIR_IY, source, soffset + i, f_dead, true)) &&
5018 result->type == AOP_REG && (i + 1 > size || soffset + i < source->size))
5020 if (IS_TLCS90 && result->type == AOP_REG && !aopInReg (result, roffset + i, IYL_IDX) && !aopInReg (result, roffset + i, IYH_IDX))
5022 if (!regalloc_dry_run)
5023 emit2 ("ld %s, !mems", aopGet (result, roffset + i, false), aopGetLitWordLong (source, soffset + i, false));
5024 cost (4, 10);
5025 i++;
5026 continue;
5028 else
5030 emit2 ("ld a, !mems", aopGetLitWordLong (source, soffset + i, false));
5031 cost2 (3 + IS_TLCS90, 13, 12, 9, 16, 10, 4, 4);
5032 via_a = true;
5033 premoved_a = true;
5036 else if ((requiresHL (result) && result->type != AOP_REG || requiresHL (source) && source->type != AOP_REG && soffset + i < source->size) && !hl_dead)
5038 via_a = aopInReg (result, roffset + i, L_IDX) || aopInReg (result, roffset + i, H_IDX);
5039 if (via_a && !a_dead)
5040 _push (PAIR_AF);
5041 if (via_a && source->type == AOP_HL)
5043 emit2 ("ld a, !mems", aopGetLitWordLong (source, soffset + i, false));
5044 cost2 (3 + IS_TLCS90, 13, 12, 9, 16, 10, 4, 4);
5045 premoved_a = true;
5047 else
5049 _push (PAIR_HL);
5050 pushed_hl = true;
5053 else if (result->type == AOP_IY && !iy_dead && !aopInReg (source, soffset + i, A_IDX))
5055 via_a = true;
5056 if (!a_dead)
5057 _push (PAIR_AF);
5059 else if (!premoved_a && source->type == AOP_IY && result->type == AOP_REG && a_dead && i == 0 && i + 1 == size) // Using free a is cheaper than using iy.
5060 via_a = true;
5061 if (!premoved_a)
5063 bool save_iy = !iy_dead && source->type == AOP_IY && (result->type == AOP_REG && !via_a && !aopInReg (result, roffset + i, A_IDX));
5064 if (save_iy)
5065 _push (PAIR_IY);
5066 cheapMove (via_a ? ASMOP_A : result, via_a ? 0 : (roffset + i), source, soffset + i, via_a || a_dead);
5067 if (save_iy)
5068 _pop (PAIR_IY);
5070 if (pushed_hl)
5071 _pop (PAIR_HL);
5072 if (via_a)
5074 if (requiresHL (result) && result->type != AOP_REG && !hl_dead)
5076 if (result->type == AOP_HL)
5078 emit2 ("ld !mems, a", aopGetLitWordLong (result, roffset + i, FALSE));
5079 cost2 (3, 13, 13, 10, 16, 10, 4, 4);
5081 else
5083 _push (PAIR_HL);
5084 cheapMove (result, roffset + i, ASMOP_A, 0, true);
5085 _pop (PAIR_HL);
5088 else
5089 cheapMove (result, roffset + i, ASMOP_A, 0, true);
5090 if (!a_dead)
5091 _pop (PAIR_AF);
5093 zeroed_a = false;
5096 i++;
5100 /*-----------------------------------------------------------------*/
5101 /* genMove - Copy the value from one asmop to another */
5102 /*-----------------------------------------------------------------*/
5103 static void
5104 genMove (asmop *result, asmop *source, bool a_dead, bool hl_dead, bool de_dead, bool iy_dead)
5106 wassert (result);
5107 genMove_o (result, 0, source, 0, result->size, a_dead, hl_dead, de_dead, iy_dead, true);
5110 /*--------------------------------------------------------------------------*/
5111 /* adjustStack - Adjust the stack pointer by n bytes. */
5112 /*--------------------------------------------------------------------------*/
5113 static void
5114 adjustStack (int n, bool af_free, bool bc_free, bool de_free, bool hl_free, bool iy_free)
5116 if(n != 0)
5117 emitDebug("; adjustStack by %d", n);
5118 _G.stack.pushed -= n;
5120 iy_free &= !IS_SM83;
5122 int loop_bytes, loop_cycles;
5123 if (abs(n) > 0 && (IS_RAB || IS_SM83)) // Assume sequence of add sp, #d
5125 loop_bytes = (abs(n) / 127 + 1) * 2;
5126 loop_cycles = (abs(n) / 127 + 1) * (IS_RAB ? 4 : 16);
5128 else if (n > 0 && (IS_Z80 || IS_Z80N || optimize.codeSize) && // Assume sequence of pop rr
5129 (!IS_TLCS90 && af_free || bc_free || de_free || hl_free || IS_TLCS90 && iy_free))
5131 loop_bytes = n / 2 + n % 2;
5132 if (IS_RAB)
5133 loop_cycles = n / 2 * 7 + n % 2 * 2;
5134 else if (IS_SM83)
5135 loop_cycles = n / 2 * 12 + n % 2 * 8;
5136 else if (IS_R800)
5137 loop_cycles = n / 2 * 4 + n % 2;
5138 else // Z80
5139 loop_cycles = n / 2 * 10 + n % 2 * 6;
5141 else // Assume sequence of inc / dec sp
5143 loop_bytes = abs(n);
5144 if (IS_RAB)
5145 loop_cycles = abs(n) * 2;
5146 else if (IS_SM83)
5147 loop_cycles = abs(n) * 8;
5148 else if (IS_R800)
5149 loop_cycles = abs(n);
5150 else // Z80
5151 loop_cycles = abs(n) * 6;
5154 if (IS_TLCS90 && abs(n) > (optimize.codeSize ? 2 + (bc_free || de_free || hl_free || iy_free || n < 0) * 2 : 1))
5156 emit2 ("add sp, !immed%d", n);
5157 cost (3, 6);
5158 n -= n;
5160 else if ((optimize.codeSpeed ?
5161 (loop_cycles >= (IS_RAB ? 10 : IS_SM83 ? 28 : 27)) :
5162 (loop_bytes >= 5)) &&
5163 hl_free)
5165 emit2 ("ld hl, !immed%d", n);
5166 emit2 ("add hl, sp");
5167 emit2 ("ld sp, hl");
5168 spillPair (PAIR_HL);
5169 cost2 (5, 27, 20, 10, 28, 18, 4, 5);
5170 n -= n;
5172 else if ((optimize.codeSpeed ?
5173 (loop_cycles >= (IS_RAB ? 14 : 35)) :
5174 (loop_bytes >= 7)) &&
5175 hl_free)
5177 emit2 ("ex de, hl");
5178 emit2 ("ld hl, !immed%d", n);
5179 emit2 ("add hl, sp");
5180 emit2 ("ld sp, hl");
5181 emit2 ("ex de, hl");
5182 spillPair (PAIR_DE);
5183 cost2 (7, 35, 26, 14, 0, 22, 6, 7);
5184 n -= n;
5186 else if ((optimize.codeSpeed ?
5187 (loop_cycles >= (IS_RAB ? 16 : 39)) :
5188 (loop_bytes >= (IS_TLCS90 ? 7 : 8))) &&
5189 iy_free)
5191 emit2 ("ld iy, !immed%d", n);
5192 emit2 ("add iy, sp");
5193 emit2 ("ld sp, iy");
5194 spillPair (PAIR_IY);
5195 cost2 (IS_TLCS90 ? 7 : 8, 39, 26, 16, 0, 20, 8, 8);
5196 n -= n;
5198 else if (loop_bytes >= 9 && bc_free)
5200 emit3 (A_LD, ASMOP_C, ASMOP_L);
5201 emit3 (A_LD, ASMOP_B, ASMOP_H);
5202 emit2 ("ld hl, !immed%d", n);
5203 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
5204 emit2 ("add hl, sp");
5205 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
5206 emit2 ("ld sp, hl");
5207 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5208 emit3 (A_LD, ASMOP_L, ASMOP_C);
5209 emit3 (A_LD, ASMOP_H, ASMOP_B);
5210 n -= n;
5213 while (abs(n))
5215 if ((IS_RAB && abs(n) > (optimize.codeSize ? 2 : 1) ) || (IS_SM83 && abs(n) > 2))
5216 { // on sm83 inc/dec is nicer for 2B because it touches no flags
5217 int d;
5218 if (n > 127)
5219 d = 127;
5220 else if (n < -128)
5221 d = -128;
5222 else
5223 d = n;
5224 emit2 ("add sp, !immed%d", d);
5225 cost (2, IS_SM83 ? 16 : 4);
5226 n -= d;
5228 // on sm83 pop is smaller and faster, but that makes detection of uninitialized memory harder
5229 // On TLCS-90 pop af messes up interrupts (unless we have a valid value for f on the stack from previous push af).
5230 else if (!IS_SM83 && !IS_TLCS90 && n >= 2 && af_free && ((IS_Z80 || IS_Z80N) || optimize.codeSize))
5232 emit2 ("pop af");
5233 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5234 n -= 2;
5236 else if (!IS_SM83 && n <= -2 && ((IS_Z80 || IS_Z80N) || optimize.codeSize))
5238 emit2 ("push af");
5239 cost2 (1, 10, 11, 7, 12, 10, 3, 4);
5240 n += 2;
5242 else if (!IS_SM83 && n >= 2 && bc_free && ((IS_Z80 || IS_Z80N) || optimize.codeSize))
5244 emit2 ("pop bc");
5245 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5246 n -= 2;
5248 else if (!IS_SM83 && n >= 2 && de_free && ((IS_Z80 || IS_Z80N) || optimize.codeSize))
5250 emit2 ("pop de");
5251 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5252 n -= 2;
5254 else if (!IS_SM83 && n >= 2 && hl_free && ((IS_Z80 || IS_Z80N) || optimize.codeSize))
5256 emit2 ("pop hl");
5257 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5258 n -= 2;
5260 else if (IS_TLCS90 && n >= 2 && iy_free && optimize.codeSize)
5262 emit2 ("pop iy");
5263 cost (1, 10);
5264 n -= 2;
5266 else if (n >= 1)
5268 emit2 ("inc sp");
5269 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5270 n--;
5272 else if (n <= -1)
5274 emit2 ("dec sp");
5275 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5276 n++;
5280 wassert(!n);
5283 /** Put Acc into a register set
5285 static void
5286 outAcc (operand * result)
5288 int size = result->aop->size;
5289 if (size)
5291 cheapMove (result->aop, 0, ASMOP_A, 0, true);
5292 size--;
5293 genMove_o (result->aop, 1, ASMOP_ZERO, 0, size, true, false, false, true, true);
5297 /** Take the value in carry and put it into a register
5299 static void
5300 outBitC (operand *result)
5302 /* if the result is bit */
5303 if (result->aop->type == AOP_CRY)
5305 if (!IS_OP_RUONLY (result) && !regalloc_dry_run)
5306 aopPut (result->aop, "c", 0); // Todo: Cost.
5308 else
5310 emit3 (A_LD, ASMOP_A, ASMOP_ZERO);
5311 emit3 (A_RLA, 0, 0);
5312 outAcc (result);
5316 /*-----------------------------------------------------------------*/
5317 /* toBoolean - emit code for or a,operator(sizeop) */
5318 /*-----------------------------------------------------------------*/
5319 static void
5320 _toBoolean (const operand *oper, bool needflag)
5322 int size = oper->aop->size;
5323 sym_link *type = operandType (oper);
5324 int skipbyte;
5326 if (size == 1 && needflag)
5328 cheapMove (ASMOP_A, 0, oper->aop, 0, true);
5329 emit3 (A_OR, ASMOP_A, ASMOP_A);
5330 return;
5333 if (size == 2 && oper->aop->type == AOP_STL)
5335 _push(PAIR_HL);
5336 genMove (ASMOP_HL, oper->aop, true, false, false, false);
5337 emit2 ("ld a, l");
5338 emit2 ("or a, h");
5339 _pop (PAIR_HL);
5340 return;
5343 // Special handling to not overwrite a.
5344 if (oper->aop->regs[A_IDX] >= 0)
5345 skipbyte = oper->aop->regs[A_IDX];
5346 else
5348 cheapMove (ASMOP_A, 0, oper->aop, size - 1, true);
5349 skipbyte = size - 1;
5352 if (IS_FLOAT (type))
5354 if (skipbyte != size - 1)
5355 UNIMPLEMENTED;
5356 emit2 ("res 7, a"); // clear sign bit
5357 cost2 (2, 8, 7, 4, 8, 4, 2, 2);
5358 skipbyte = size - 1;
5360 while (size--)
5361 if (size != skipbyte)
5363 if (!HAS_IYL_INST && (aopInReg (oper->aop, size, IYL_IDX) || aopInReg (oper->aop, size, IYH_IDX)))
5364 UNIMPLEMENTED;
5365 else
5366 emit3_o (A_OR, ASMOP_A, 0, oper->aop, size);
5370 /*-----------------------------------------------------------------*/
5371 /* castBoolean - emit code for casting operand to boolean in a */
5372 /*-----------------------------------------------------------------*/
5373 static void
5374 _castBoolean (const operand *right)
5376 emitDebug ("; Casting to bool");
5378 /* Can do without OR-ing for small arguments */
5379 if (right->aop->size == 1 && !aopInReg (right->aop, 0, A_IDX))
5381 emit3 (A_XOR, ASMOP_A, ASMOP_A);
5382 if (!HAS_IYL_INST && (aopInReg (right->aop, 0, IYL_IDX) || aopInReg (right->aop, 0, IYH_IDX)))
5383 UNIMPLEMENTED;
5384 else
5385 emit3 (A_CP, ASMOP_A, right->aop);
5387 else
5389 _toBoolean (right, FALSE);
5390 emit2 ("add a, !immedbyte", 0xffu);
5391 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
5392 emit3 (A_LD, ASMOP_A, ASMOP_ZERO);
5394 emit3 (A_RLA, 0, 0);
5397 /* Shuffle src reg array into dst reg array. */
5398 static void
5399 regMove (const short *dst, const short *src, size_t n, bool preserve_a) // Todo: replace uses of this one by uses of genMove_o?
5401 bool assigned[9] = { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE };
5402 int cached_byte = -1;
5403 size_t size = n;
5404 int ex[4] = {-1, -1, -1, -1};
5405 size_t i;
5406 bool pushed_a = FALSE;
5408 wassert (n <= 9);
5410 // Try to use ex de, hl
5411 if (size >= 4)
5413 // Find E and check that it is exchanged with L.
5414 for (i = 0; i < n; i++)
5415 if (dst[i] == E_IDX && src[i] == L_IDX)
5416 ex[0] = i;
5417 for (i = 0; i < n; i++)
5418 if (dst[i] == L_IDX && src[i] == E_IDX)
5419 ex[1] = i;
5420 // Find D and check that it is exchanged with H.
5421 for (i = 0; i < n; i++)
5422 if (dst[i] == D_IDX && src[i] == H_IDX)
5423 ex[2] = i;
5424 for (i = 0; i < n; i++)
5425 if (dst[i] == H_IDX && src[i] == D_IDX)
5426 ex[3] = i;
5427 if (ex[0] >= 0 && ex[1] >= 0 && ex[2] >= 0 && ex[3] >= 0)
5429 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
5430 swapPairs (PAIR_DE, PAIR_HL);
5431 assigned[ex[0]] = true;
5432 assigned[ex[1]] = true;
5433 assigned[ex[2]] = true;
5434 assigned[ex[3]] = true;
5435 size -= 4;
5439 // We need to be able to handle any assignment here, ensuring not to overwrite any parts of the source that we still need.
5440 while (size)
5442 // Find lowest byte that can be assigned and needs to be assigned.
5443 for (i = 0; i < n; i++)
5445 size_t j;
5447 if (assigned[i])
5448 continue;
5450 for (j = 0; j < n; j++)
5452 if (!assigned[j] && i != j && dst[i] == src[j])
5453 goto skip_byte; // We can't write this one without overwriting the source.
5456 break; // Found byte that can be written safely.
5458 skip_byte:
5462 if (i < n)
5464 cheapMove (asmopregs[dst[i]], 0, asmopregs[src[i]], 0, false); // We can safely assign a byte.
5465 size--;
5466 assigned[i] = TRUE;
5467 continue;
5470 // No byte can be assigned safely (i.e. the assignment is a permutation). Cache one in the accumulator.
5472 if (cached_byte != -1)
5474 // Already one cached. Can happen when the assignment is a permutation consisting of multiple cycles.
5475 cheapMove (asmopregs[dst[cached_byte]], 0, ASMOP_A, 0, true);
5476 cached_byte = -1;
5477 continue;
5480 for (i = 0; i < n; i++)
5481 if (!assigned[i])
5482 break;
5484 wassertl (i != n, "regMove error: Trying to cache non-existent byte in accumulator.");
5485 if (preserve_a && !pushed_a)
5487 _push (PAIR_AF);
5488 pushed_a = TRUE;
5490 cheapMove (ASMOP_A, 0, asmopregs[src[i]], 0, true);
5491 size--;
5492 assigned[i] = TRUE;
5493 cached_byte = i;
5496 if (cached_byte != -1)
5497 cheapMove (asmopregs[dst[cached_byte]], 0, ASMOP_A, 0, true);
5499 if (pushed_a)
5500 _pop (PAIR_AF);
5503 /*-----------------------------------------------------------------*/
5504 /* genNot - generate code for ! operation */
5505 /*-----------------------------------------------------------------*/
5506 static void
5507 genNot (const iCode * ic)
5509 operand *left = IC_LEFT (ic);
5510 operand *result = IC_RESULT (ic);
5512 /* assign asmOps to operand & result */
5513 aopOp (left, ic, FALSE, TRUE);
5514 aopOp (result, ic, TRUE, FALSE);
5516 /* if in bit space then a special case */
5517 if (left->aop->type == AOP_CRY)
5519 wassertl (0, "Tried to negate a bit");
5521 else if (IS_BOOL (operandType (left)))
5523 cheapMove (ASMOP_A, 0, left->aop, 0, true);
5524 emit3 (A_XOR, ASMOP_A, ASMOP_ONE);
5525 cheapMove (result->aop, 0, ASMOP_A, 0, true);
5526 goto release;
5528 else if (IS_RAB && left->aop->size == 2 && aopInReg (left->aop, 0, HL_IDX) && isPairDead (PAIR_HL, ic) && aopInReg (result->aop, 0, L_IDX))
5530 emit2 ("bool hl");
5531 emit2 ("rr hl");
5532 emit2 ("ccf");
5533 emit2 ("adc hl, hl");
5534 cost (5, 10);
5535 goto release;
5537 else if (IS_RAB && left->aop->size == 2 && aopInReg (left->aop, 0, HL_IDX) && isPairDead (PAIR_HL, ic))
5539 emit2 ("bool hl");
5540 emit2 ("ld a, l");
5541 emit2 ("xor a, #0x01");
5542 cost (4, 8);
5543 cheapMove (result->aop, 0, ASMOP_A, 0, true);
5544 goto release;
5547 _toBoolean (left, FALSE);
5549 /* Not of A:
5550 If A == 0, !A = 1
5551 else A = 0
5552 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
5553 emit3 (A_SUB, ASMOP_A, ASMOP_ONE);
5554 outBitC (result);
5556 release:
5557 /* release the aops */
5558 freeAsmop (left, NULL);
5559 freeAsmop (result, NULL);
5562 static void
5563 _gbz80_emitAddSubLongLong (const iCode * ic, asmop * left, asmop * right, bool isAdd)
5565 enum asminst first = isAdd ? A_ADD : A_SUB;
5566 enum asminst later = isAdd ? A_ADC : A_SBC;
5569 /* Logic:
5570 ld de,right.lw
5571 setup hl to left
5572 de = hl - de
5573 push flags
5574 store de into result
5575 pop flags
5576 ld de,right.hw
5577 setup hl
5578 de = hl -de
5579 store de into result
5582 wassertl (IS_SM83, "Code is only relevant to the gbz80");
5583 wassertl (IC_RESULT (ic)->aop->size == 4, "Only works for four bytes");
5585 fetchPair (PAIR_DE, left);
5587 emit3 (A_LD, ASMOP_A, ASMOP_E);
5588 emit3_o (first, ASMOP_A, 0, right, LSB);
5589 emit2 ("ld e, a");
5590 emit3 (A_LD, ASMOP_E, ASMOP_A);
5591 emit3 (A_LD, ASMOP_A, ASMOP_D);
5592 emit3_o (later, ASMOP_A, 0, right, MSB16);
5594 _push (PAIR_AF);
5596 cheapMove (IC_RESULT (ic)->aop, MSB16, ASMOP_A, 0, true);
5597 cheapMove (IC_RESULT (ic)->aop, LSB, ASMOP_E, 0, true);
5599 fetchPairLong (PAIR_DE, left, NULL, MSB24);
5601 if (!regalloc_dry_run)
5602 aopGet (right, MSB24, FALSE);
5604 _pop (PAIR_AF);
5605 emit3 (A_LD, ASMOP_A, ASMOP_E);
5606 emit3_o (later, ASMOP_A, 0, right, MSB24);
5607 emit3 (A_LD, ASMOP_E, ASMOP_A);
5608 emit3 (A_LD, ASMOP_A, ASMOP_D);
5609 emit3_o (later, ASMOP_A, 0, right, MSB32);
5611 cheapMove (IC_RESULT (ic)->aop, MSB32, ASMOP_A, 0, true);
5612 cheapMove (IC_RESULT (ic)->aop, MSB24, ASMOP_E, 0, true);
5615 static void
5616 _gbz80_emitAddSubLong (const iCode * ic, bool isAdd)
5618 _gbz80_emitAddSubLongLong (ic, IC_LEFT (ic)->aop, IC_RIGHT (ic)->aop, isAdd);
5621 /* Pop saved regs from stack, taking care not to destroy result */
5622 static void
5623 restoreRegs (bool iy, bool de, bool bc, bool hl, const operand *result, const iCode *const ic)
5625 bool a_live, b_live, c_live, d_live, e_live, h_live, l_live, iyl_live, iyh_live;
5626 bool SomethingReturned;
5628 SomethingReturned = result && IS_ITEMP (result) && (OP_SYMBOL_CONST (result)->nRegs || OP_SYMBOL_CONST (result)->spildir)
5629 || IS_TRUE_SYMOP (result);
5631 if (SomethingReturned)
5633 bitVect *rv = z80_rUmaskForOp (result);
5634 a_live = bitVectBitValue (rv, A_IDX);
5635 b_live = bitVectBitValue (rv, B_IDX);
5636 c_live = bitVectBitValue (rv, C_IDX);
5637 d_live = bitVectBitValue (rv, D_IDX);
5638 e_live = bitVectBitValue (rv, E_IDX);
5639 h_live = bitVectBitValue (rv, H_IDX);
5640 l_live = bitVectBitValue (rv, L_IDX);
5641 iyh_live = bitVectBitValue (rv, IYH_IDX);
5642 iyl_live = bitVectBitValue (rv, IYL_IDX);
5643 freeBitVect (rv);
5645 else
5647 a_live = false;
5648 b_live = false;
5649 c_live = false;
5650 d_live = false;
5651 e_live = false;
5652 h_live = false;
5653 l_live = false;
5654 iyh_live = false;
5655 iyl_live = false;
5658 if (ic)
5660 if (!isRegDead (A_IDX, ic))
5661 a_live = true;
5662 if (!de && !isRegDead (D_IDX, ic))
5663 d_live = true;
5664 if (!de && !isRegDead (E_IDX, ic))
5665 e_live = true;
5666 if (!bc && !isRegDead (B_IDX, ic))
5667 b_live = true;
5668 if (!bc && !isRegDead (C_IDX, ic))
5669 c_live = true;
5670 if (!hl && !isRegDead (H_IDX, ic))
5671 h_live = true;
5672 if (!hl && !isRegDead (L_IDX, ic))
5673 l_live = true;
5674 if (!iy && !isRegDead (IYH_IDX, ic))
5675 iyh_live = true;
5676 if (!iy && !isRegDead (IYL_IDX, ic))
5677 iyl_live = true;
5680 if (iy)
5682 if (iyh_live && iyl_live)
5683 wassertl (0, "Shouldn't push IY if it's wiped out by the return");
5684 else if (iyh_live)
5685 poppairwithsavedreg (PAIR_IY, IYH_IDX, -1);
5686 else if (iyl_live)
5687 poppairwithsavedreg (PAIR_IY, IYL_IDX, -1);
5688 else
5689 _pop (PAIR_IY);
5692 if (de)
5694 if (d_live && e_live)
5695 wassertl (0, "Shouldn't push DE if it's wiped out by the return");
5696 else if (d_live && !a_live)
5697 poppairwithsavedreg (PAIR_DE, D_IDX, A_IDX);
5698 else if (d_live && !h_live)
5699 poppairwithsavedreg (PAIR_DE, D_IDX, H_IDX);
5700 else if (d_live && !b_live)
5701 poppairwithsavedreg (PAIR_DE, D_IDX, B_IDX);
5702 else if (d_live)
5703 poppairwithsavedreg (PAIR_DE, D_IDX, -1);
5704 else if (e_live && !a_live && !IS_TLCS90) // TLCS-90 has interrupt settings in f, so we can't pop af unless we did push af before.
5706 /* Only restore D */
5707 _pop (PAIR_AF);
5708 emit2 ("ld d, a");
5709 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
5711 else if (e_live && !a_live)
5712 poppairwithsavedreg (PAIR_DE, E_IDX, A_IDX);
5713 else if (e_live && !l_live)
5714 poppairwithsavedreg (PAIR_DE, E_IDX, L_IDX);
5715 else if (e_live && !c_live)
5716 poppairwithsavedreg (PAIR_DE, E_IDX, C_IDX);
5717 else if (e_live)
5718 poppairwithsavedreg (PAIR_DE, E_IDX, -1);
5719 else
5720 _pop (PAIR_DE);
5723 if (bc)
5725 if (b_live && c_live)
5726 wassertl (0, "Shouldn't push BC if it's wiped out by the return");
5727 else if (b_live && !a_live)
5728 poppairwithsavedreg (PAIR_BC, B_IDX, A_IDX);
5729 else if (b_live && !h_live)
5730 poppairwithsavedreg (PAIR_BC, B_IDX, H_IDX);
5731 else if (b_live && !l_live)
5732 poppairwithsavedreg (PAIR_BC, B_IDX, L_IDX);
5733 else if (b_live)
5734 poppairwithsavedreg (PAIR_BC, B_IDX, -1);
5735 else if (c_live && !a_live && !IS_TLCS90)
5737 /* Only restore B */
5738 _pop (PAIR_AF);
5739 emit2 ("ld b, a");
5740 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
5742 else if (c_live && !a_live)
5743 poppairwithsavedreg (PAIR_BC, C_IDX, A_IDX);
5744 else if (c_live && !l_live)
5745 poppairwithsavedreg (PAIR_BC, C_IDX, L_IDX);
5746 else if (c_live && !h_live)
5747 poppairwithsavedreg (PAIR_BC, C_IDX, H_IDX);
5748 else if (c_live)
5749 poppairwithsavedreg (PAIR_BC, C_IDX, -1);
5750 else
5751 _pop (PAIR_BC);
5754 if (hl)
5756 if (h_live && l_live)
5757 wassertl (0, "Shouldn't push HL if it's wiped out by the return");
5758 else if (h_live && !a_live)
5759 poppairwithsavedreg (PAIR_HL, H_IDX, A_IDX);
5760 else if (h_live && !bc && !b_live)
5761 poppairwithsavedreg (PAIR_HL, H_IDX, B_IDX);
5762 else if (h_live && !de && !d_live)
5763 poppairwithsavedreg (PAIR_HL, H_IDX, D_IDX);
5764 else if (h_live && !bc && !c_live)
5765 poppairwithsavedreg (PAIR_HL, H_IDX, C_IDX);
5766 else if (h_live && !de && !e_live)
5767 poppairwithsavedreg (PAIR_HL, H_IDX, E_IDX);
5768 else if (h_live)
5769 poppairwithsavedreg (PAIR_HL, H_IDX, -1);
5770 else if (l_live && !a_live && !IS_TLCS90)
5772 /* Only restore H */
5773 _pop (PAIR_AF);
5774 emit2 ("ld h, a");
5775 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
5777 else if (l_live&& !a_live )
5778 poppairwithsavedreg (PAIR_HL, L_IDX, A_IDX);
5779 else if (l_live && !bc && !c_live )
5780 poppairwithsavedreg (PAIR_HL, L_IDX, C_IDX);
5781 else if (l_live && !de && !e_live )
5782 poppairwithsavedreg (PAIR_HL, L_IDX, E_IDX);
5783 else if (l_live && !bc && !b_live )
5784 poppairwithsavedreg (PAIR_HL, L_IDX, B_IDX);
5785 else if (l_live && !de && !d_live )
5786 poppairwithsavedreg (PAIR_HL, L_IDX, D_IDX);
5787 else if (l_live)
5788 poppairwithsavedreg (PAIR_HL, L_IDX, -1);
5789 else
5790 _pop (PAIR_HL);
5794 static void
5795 _saveRegsForCall (const iCode *ic, bool saveHLifused, bool dontsaveIY)
5797 /* Rules:
5798 o Stack parameters are pushed before this function enters
5799 o DE and BC may be used in this function.
5800 o HL and DE may be used to return the result.
5801 o HL and DE may be used to send variables.
5802 o DE and BC may be used to store the result value.
5803 o HL may be used in computing the sent value of DE
5804 o The iPushes for other parameters occur before any addSets
5806 Logic: (to be run inside the first iPush or if none, before sending)
5807 o Compute if DE, BC, HL, IY are in use over the call
5808 o Compute if DE is used in the send set
5809 o Compute if DE and/or BC are used to hold the result value
5810 o If (DE is used, or in the send set) and is not used in the result, push.
5811 o If BC is used and is not in the result, push
5813 o If DE is used in the send set, fetch
5814 o If HL is used in the send set, fetch
5815 o Call
5816 o ...
5819 sym_link *dtype = operandType (IC_LEFT (ic));
5820 sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype;
5822 if (IS_FUNCPTR (dtype))
5823 saveHLifused = true;
5824 if (!_G.saves.saved)
5826 const bool call_preserves_b = ftype->funcAttrs.preserved_regs[B_IDX] && !z80IsParmInCall(ftype, "b");
5827 const bool call_preserves_c = ftype->funcAttrs.preserved_regs[C_IDX] && !z80IsParmInCall(ftype, "c");
5828 const bool call_preserves_d = ftype->funcAttrs.preserved_regs[D_IDX] && !z80IsParmInCall(ftype, "d");
5829 const bool call_preserves_e = ftype->funcAttrs.preserved_regs[E_IDX] && !z80IsParmInCall(ftype, "e");
5830 const bool call_preserves_h = ftype->funcAttrs.preserved_regs[H_IDX] && !z80IsParmInCall(ftype, "h");
5831 const bool call_preserves_l = ftype->funcAttrs.preserved_regs[L_IDX] && !z80IsParmInCall(ftype, "l");
5832 const bool push_bc = !isRegDead (B_IDX, ic) && !call_preserves_b || !isRegDead (C_IDX, ic) && !call_preserves_c;
5833 const bool push_de = !isRegDead (D_IDX, ic) && !call_preserves_d || !isRegDead (E_IDX, ic) && !call_preserves_e;
5834 const bool push_hl = !isRegDead (H_IDX, ic) && (!call_preserves_h || saveHLifused) || !isRegDead (L_IDX, ic) && (!call_preserves_l || saveHLifused);
5835 const bool push_iy = !dontsaveIY && (!isRegDead (IYH_IDX, ic) || !isRegDead (IYL_IDX, ic));
5837 if (push_hl)
5839 _push (PAIR_HL);
5840 _G.stack.pushedHL = TRUE;
5842 if (push_bc)
5844 _push (PAIR_BC);
5845 _G.stack.pushedBC = TRUE;
5847 if (push_de)
5849 _push (PAIR_DE);
5850 _G.stack.pushedDE = TRUE;
5852 if (push_iy)
5854 _push (PAIR_IY);
5855 _G.stack.pushedIY = TRUE;
5858 if (!regalloc_dry_run)
5859 _G.saves.saved = TRUE;
5861 else
5863 /* Already saved. */
5867 /*-----------------------------------------------------------------*/
5868 /* genIpush - genrate code for pushing this gets a little complex */
5869 /*-----------------------------------------------------------------*/
5870 static void
5871 genIpush (const iCode *ic)
5873 /* if this is not a parm push : ie. it is spill push
5874 and spill push is always done on the local stack */
5875 if (!ic->parmPush)
5877 wassertl (0, "Encountered an unsupported spill push.");
5878 return;
5881 /* Scan ahead until we find the function that we are pushing parameters to.
5882 Count the number of addSets on the way to figure out what registers
5883 are used in the send set.
5885 int nAddSets = 0;
5886 iCode *walk = ic->next;
5888 while (walk)
5890 if (walk->op == SEND && !_G.saves.saved && !regalloc_dry_run)
5891 nAddSets++;
5892 else if (walk->op == CALL || walk->op == PCALL)
5893 break; // Found it.
5895 walk = walk->next; // Keep looking.
5897 if (!regalloc_dry_run && !_G.saves.saved && !regalloc_dry_run) /* Cost is counted at CALL or PCALL instead */
5898 _saveRegsForCall (walk, true, false); /* Caller saves, and this is the first iPush. */
5900 sym_link *ftype = operandType (IC_LEFT (walk));
5901 if (walk->op == PCALL)
5902 ftype = ftype->next;
5903 const bool smallc = IFFUNC_ISSMALLC (ftype);
5905 /* then do the push */
5906 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
5908 int size = IC_LEFT (ic)->aop->size;
5910 if (size == 1 && smallc) /* The SmallC calling convention pushes 8-bit parameters as 16-bit values. */
5912 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX)
5914 emit2 ("push bc");
5915 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5917 else if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX)
5919 emit2 ("push de");
5920 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5922 else if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX)
5924 emit2 ("push hl");
5925 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5927 else if (isRegDead (HL_IDX, ic))
5929 cheapMove (ASMOP_L, 0, IC_LEFT (ic)->aop, 0, true);
5930 emit2 ("push hl");
5931 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5933 else if (isRegDead (A_IDX, ic))
5935 emit2 ("dec sp");
5936 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5937 cheapMove (ASMOP_A, 0, IC_LEFT (ic)->aop, 0, true);
5938 emit2 ("push af");
5939 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5940 emit2 ("inc sp");
5941 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5943 else if (!IS_SM83)
5945 emit2 ("push hl");
5946 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5947 cheapMove (ASMOP_L, 0, IC_LEFT (ic)->aop, 0, false);
5948 emit2 ("ex (sp), hl");
5949 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
5950 spillPair (PAIR_HL);
5952 else
5953 wassert (0);
5955 if (!regalloc_dry_run)
5956 _G.stack.pushed += 2;
5957 goto release;
5960 while (size)
5962 int d = 0;
5964 bool a_free = isRegDead (A_IDX, ic) && (IC_LEFT (ic)->aop->regs[A_IDX] < 0 || IC_LEFT (ic)->aop->regs[A_IDX] >= size - 1);
5965 bool b_free = isRegDead (B_IDX, ic) && (IC_LEFT (ic)->aop->regs[B_IDX] < 0 || IC_LEFT (ic)->aop->regs[B_IDX] >= size - 1);
5966 bool c_free = isRegDead (C_IDX, ic) && (IC_LEFT (ic)->aop->regs[C_IDX] < 0 || IC_LEFT (ic)->aop->regs[C_IDX] >= size - 1);
5967 bool d_free = isRegDead (D_IDX, ic) && (IC_LEFT (ic)->aop->regs[D_IDX] < 0 || IC_LEFT (ic)->aop->regs[D_IDX] >= size - 1);
5968 bool e_free = isRegDead (E_IDX, ic) && (IC_LEFT (ic)->aop->regs[E_IDX] < 0 || IC_LEFT (ic)->aop->regs[E_IDX] >= size - 1);
5969 bool h_free = isRegDead (H_IDX, ic) && (IC_LEFT (ic)->aop->regs[H_IDX] < 0 || IC_LEFT (ic)->aop->regs[H_IDX] >= size - 1);
5970 bool l_free = isRegDead (L_IDX, ic) && (IC_LEFT (ic)->aop->regs[L_IDX] < 0 || IC_LEFT (ic)->aop->regs[L_IDX] >= size - 1);
5971 bool iyh_free = isRegDead (IYH_IDX, ic) && (IC_LEFT (ic)->aop->regs[IYH_IDX] < 0 || IC_LEFT (ic)->aop->regs[IYH_IDX] >= size - 1);
5972 bool iyl_free = isRegDead (IYL_IDX, ic) && (IC_LEFT (ic)->aop->regs[IYL_IDX] < 0 || IC_LEFT (ic)->aop->regs[IYL_IDX] >= size - 1);
5973 bool hl_free = isPairDead (PAIR_HL, ic) && (h_free || IC_LEFT (ic)->aop->regs[H_IDX] >= size - 2) && (l_free || IC_LEFT (ic)->aop->regs[L_IDX] >= size - 2);
5974 bool de_free = isPairDead (PAIR_DE, ic) && (d_free || IC_LEFT (ic)->aop->regs[D_IDX] >= size - 2) && (e_free || IC_LEFT (ic)->aop->regs[E_IDX] >= size - 2);
5975 bool bc_free = isPairDead (PAIR_BC, ic) && (b_free || IC_LEFT (ic)->aop->regs[B_IDX] >= size - 2) && (c_free || IC_LEFT (ic)->aop->regs[C_IDX] >= size - 2);
5977 if (getPairId_o (IC_LEFT (ic)->aop, size - 2) != PAIR_INVALID)
5979 emit2 ("push %s", _pairs[getPairId_o (IC_LEFT (ic)->aop, size - 2)].name);
5980 if (getPairId_o (IC_LEFT (ic)->aop, size - 2) == PAIR_IY)
5981 cost2 (2 - IS_TLCS90, 15, 13, 12, 0, 8, 4, 5);
5982 else
5983 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5984 d = 2;
5986 #if 0 // Fails regression tests. Simulator issue regarding flags?
5987 // gbz80 flag handling differs from other z80 variants, allowing this hack to push a 16-bit zero.
5988 else if (size >= 2 && IS_SM83 && a_free &&
5989 IC_LEFT (ic)->aop->type == AOP_LIT && !byteOfVal (IC_LEFT(ic)->aop->aopu.aop_lit, size - 2) && !byteOfVal (IC_LEFT(ic)->aop->aopu.aop_lit, size - 1))
5991 emit2 ("xor a, a"); // Resets all flags except for z
5992 emit2 ("rra"); // Resets z (and since a is already 0, c stays reset)
5993 emit2 ("push af"); // Pushes 0 in a, 0 for the unused upper 4 flag bits, 4 flag bits that are all reset, giving us a 16-bit 0 push.
5994 regalloc_dry_run_cost += 3;
5995 d = 2;
5997 #endif
5998 else if (size >= 2 &&
5999 (hl_free || de_free || bc_free ||
6000 aopInReg (IC_LEFT (ic)->aop, size - 1, B_IDX) && c_free || b_free && aopInReg (IC_LEFT (ic)->aop, size - 2, C_IDX) ||
6001 aopInReg (IC_LEFT (ic)->aop, size - 1, D_IDX) && e_free || d_free && aopInReg (IC_LEFT (ic)->aop, size - 2, E_IDX) ||
6002 aopInReg (IC_LEFT (ic)->aop, size - 1, H_IDX) && l_free || h_free && aopInReg (IC_LEFT (ic)->aop, size - 2, L_IDX)))
6004 asmop *pair = 0;
6006 /* hl has lower priority on GB, because it's needed for stack access */
6007 if (!IS_SM83 && hl_free)
6008 pair = ASMOP_HL;
6009 else if (de_free)
6010 pair = ASMOP_DE;
6011 else if (bc_free)
6012 pair = ASMOP_BC;
6013 else if (hl_free)
6014 pair = ASMOP_HL;
6016 if (IS_SM83 && requiresHL (IC_LEFT (ic)->aop) && IC_LEFT (ic)->aop->type != AOP_REG && de_free)
6017 pair = ASMOP_DE;
6018 else if (IS_SM83 && requiresHL (IC_LEFT (ic)->aop) && IC_LEFT (ic)->aop->type != AOP_REG && bc_free)
6019 pair = ASMOP_BC;
6021 if (aopInReg (IC_LEFT (ic)->aop, size - 1, H_IDX) && l_free || h_free && aopInReg (IC_LEFT (ic)->aop, size - 2, L_IDX))
6022 pair = ASMOP_HL;
6023 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, D_IDX) && e_free || d_free && aopInReg (IC_LEFT (ic)->aop, size - 2, E_IDX))
6024 pair = ASMOP_DE;
6025 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, B_IDX) && c_free || b_free && aopInReg (IC_LEFT (ic)->aop, size - 2, C_IDX))
6026 pair = ASMOP_BC;
6028 genMove_o (pair, 0, IC_LEFT (ic)->aop, size - 2, 2, a_free, hl_free, de_free, true, true);
6029 emit2 ("push %s", _pairs[getPairId (pair)].name);
6030 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6031 d = 2;
6033 // For hl and iy, genMove_o can do better caching of literal values than what we do here. TODO: Remove this, and make genMove_o handle cahing well for bc and de, too (will require quite some spillPair() calls througout codegen).
6034 while (getPairId (pair) != PAIR_HL && IC_LEFT (ic)->aop->type == AOP_LIT && !IS_FLOAT (IC_LEFT (ic)->aop->aopu.aop_lit->type) && size - (d+2) >= 0)
6036 unsigned long current = (ullFromVal(IC_LEFT (ic)->aop->aopu.aop_lit)>>((size - d )*8)) & 0xFFFF;
6037 unsigned long next = (ullFromVal(IC_LEFT (ic)->aop->aopu.aop_lit)>>((size - (d+2))*8)) & 0xFFFF;
6038 if (current == next)
6040 emitDebug ("; genIpush identical value again");
6041 emit2 ("push %s", _pairs[getPairId (pair)].name);
6042 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6043 d+=2;
6045 else if ((current & 0xFF) == (next & 0xFF))
6047 emitDebug ("; genIpush similar value again");
6048 emit2 ("ld %s, !immedbyte", _pairs[getPairId (pair)].h, (unsigned)(next >> 8));
6049 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
6050 emit2 ("push %s", _pairs[getPairId (pair)].name);
6051 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6052 d+=2;
6054 else if ((current & 0xFF00) == (next & 0xFF00))
6056 emitDebug ("; genIpush similar value again");
6057 emit2 ("ld %s, !immedbyte", _pairs[getPairId (pair)].l, (unsigned)(next & 0xffu));
6058 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
6059 emit2 ("push %s", _pairs[getPairId (pair)].name);
6060 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6061 d+=2;
6063 else
6064 break;
6067 else if (size >= 2 && IS_Z80N && (IC_LEFT (ic)->aop->type == AOP_LIT || IC_LEFT (ic)->aop->type == AOP_IMMD)) // Same size, but slower (21 vs 23 cycles) than going through a register pair other than iy. Only worth it under high register pressure.
6069 emit2 ("push !hashedstr", aopGetLitWordLong (IC_LEFT (ic)->aop, size - 2, false));
6070 cost (4, 23);
6071 d = 2;
6073 else if (size >= 2 && !IS_SM83 && !IY_RESERVED && isPairDead (PAIR_IY, ic) && (IC_LEFT (ic)->aop->type == AOP_LIT || IC_LEFT (ic)->aop->type == AOP_IMMD))
6075 genMove_o (ASMOP_IY, 0, IC_LEFT (ic)->aop, size - 2, 2, a_free, hl_free, de_free, true, true);
6076 emit2 ("push iy");
6077 cost2 (2, 1, 13, 12, 0, 8, 4, 5);
6078 d = 2;
6080 else if (size >= 2 && !IS_SM83)
6082 emit2 ("push hl");
6083 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6084 _G.stack.pushed += 2;
6085 genMove_o (ASMOP_HL, 0, IC_LEFT (ic)->aop, size - 2, 2, a_free, hl_free, de_free, true, true);
6086 _G.stack.pushed -= 2;
6087 emit2 ("ex (sp), hl");
6088 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
6089 spillPair (PAIR_HL);
6090 d = 2;
6092 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, A_IDX))
6094 emit2 ("push af");
6095 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6096 emit2 ("inc sp");
6097 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6098 d = 1;
6100 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, B_IDX))
6102 emit2 ("push bc");
6103 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6104 emit2 ("inc sp");
6105 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6106 d = 1;
6108 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, D_IDX))
6110 emit2 ("push de");
6111 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6112 emit2 ("inc sp");
6113 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6114 d = 1;
6116 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, H_IDX))
6118 emit2 ("push hl");
6119 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6120 emit2 ("inc sp");
6121 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6122 d = 1;
6124 else if (aopInReg (IC_LEFT (ic)->aop, size - 1, IYH_IDX))
6126 emit2 ("push iy");
6127 cost2 (2, 1, 13, 12, 0, 8, 4, 5);
6128 emit2 ("inc sp");
6129 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6130 d = 1;
6132 else if (a_free)
6134 genMove_o (ASMOP_A, 0, IC_LEFT (ic)->aop, size - 1, 1, a_free, h_free && l_free, d_free && e_free, iyh_free && iyl_free, true);
6135 emit2 ("push af");
6136 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6137 emit2 ("inc sp");
6138 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6139 d = 1;
6141 else if (h_free)
6143 genMove_o (ASMOP_H, 0, IC_LEFT (ic)->aop, size - 1, 1, a_free, h_free && l_free, d_free && e_free, iyh_free && iyl_free, true);
6144 emit2 ("push hl");
6145 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6146 emit2 ("inc sp");
6147 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6148 d = 1;
6150 else if (d_free)
6152 genMove_o (ASMOP_D, 0, IC_LEFT (ic)->aop, size - 1, 1, a_free, h_free && l_free, d_free && e_free, iyh_free && iyl_free, true);
6153 emit2 ("push de");
6154 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6155 emit2 ("inc sp");
6156 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6157 d = 1;
6159 else if (b_free)
6161 genMove_o (ASMOP_B, 0, IC_LEFT (ic)->aop, size - 1, 1, a_free, h_free && l_free, d_free && e_free, iyh_free && iyl_free, true);
6162 emit2 ("push bc");
6163 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6164 emit2 ("inc sp");
6165 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6166 d = 1;
6168 else if (IS_Z80N && IC_LEFT (ic)->aop->type == AOP_LIT)
6170 emit2 ("push !immedword", (unsigned)(byteOfVal (IC_LEFT (ic)->aop->aopu.aop_lit, size - 1) << 8));
6171 cost (4, 23);
6172 emit2 ("inc sp");
6173 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6174 d = 1;
6176 else if (!IS_SM83)
6178 emit2 ("push hl");
6179 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6180 genMove_o (ASMOP_H, 0, IC_LEFT (ic)->aop, size - 1, 1, a_free, h_free && l_free, d_free && e_free, iyh_free && iyl_free, true);
6181 emit2 ("ex (sp), hl");
6182 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
6183 spillPair (PAIR_HL);
6184 emit2 ("inc sp");
6185 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6186 d = 1;
6188 else
6189 wassert (0);
6191 if (!regalloc_dry_run)
6192 _G.stack.pushed += d;
6193 size -= d;
6196 release:
6197 freeAsmop (IC_LEFT (ic), NULL);
6200 /*-----------------------------------------------------------------*/
6201 /* genPointerPush - generate code for pushing */
6202 /*-----------------------------------------------------------------*/
6203 static void
6204 genPointerPush (const iCode *ic)
6206 /* Scan ahead until we find the function that we are pushing parameters to.
6207 Count the number of addSets on the way to figure out what registers
6208 are used in the send set.
6210 int nAddSets = 0;
6211 iCode *walk = ic->next;
6213 while (walk)
6215 if (walk->op == SEND && !_G.saves.saved && !regalloc_dry_run)
6216 nAddSets++;
6217 else if (walk->op == CALL || walk->op == PCALL)
6218 break; // Found it.
6220 walk = walk->next; // Keep looking.
6222 if (!regalloc_dry_run && !_G.saves.saved) /* Cost is counted at CALL or PCALL instead */
6223 _saveRegsForCall (walk, true, false); /* Caller saves, and this is the first iPush. */
6225 sym_link *ftype = operandType (IC_LEFT (walk));
6226 if (walk->op == PCALL)
6227 ftype = ftype->next;
6228 const bool smallc = IFFUNC_ISSMALLC (ftype);
6230 /* then do the push */
6231 aopOp (IC_LEFT (ic), ic, false, false);
6233 wassertl (IC_RIGHT (ic), "IPUSH_VALUE_AT_ADDRESS without right operand");
6234 wassertl (IS_OP_LITERAL (IC_RIGHT (ic)), "IPUSH_VALUE_AT_ADDRESS with non-literal right operand");
6236 int offset = operandLitValue (IC_RIGHT(ic));
6238 wassert (!offset);
6239 wassert (!smallc);
6241 if (!isRegDead (HL_IDX, ic) && !(isRegDead (DE_IDX, ic) && !IS_SM83) || !isRegDead (A_IDX, ic))
6242 UNIMPLEMENTED;
6244 bool swap_de = !isRegDead (HL_IDX, ic);
6246 if (swap_de)
6247 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
6249 genMove (ASMOP_HL, IC_LEFT (ic)->aop, true, true, swap_de ? false : isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
6251 int size = getSize (operandType (ic->left)->next);
6252 if (TARGET_IS_TLCS90 && size >= (optimize.codeSpeed? 3 : 4))
6254 emit2 ("add hl, !immed%d", size - 1);
6255 cost (3, 6);
6257 else if (isRegDead (BC_IDX, ic) && size > 5)
6259 emit2 ("ld bc, !immed%d", size - 1);
6260 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6261 emit2 ("add hl, bc");
6262 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
6264 else
6265 for(int i = 1; i < size; i++)
6266 emit3w (A_INC, ASMOP_HL, 0);
6268 for(int i = 0; i < size;)
6270 if (i + 1 < size && isRegDead (BC_IDX, ic))
6272 emit2 ("ld b, !*hl");
6273 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
6274 emit2 ("dec hl");
6275 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6276 emit2 ("ld c, !*hl");
6277 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
6278 emit2 ("push bc");
6279 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6280 _G.stack.pushed += 2;
6281 i += 2;
6283 else
6285 emit2 ("ld a, !*hl");
6286 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
6287 emit2 ("push af");
6288 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6289 emit2 ("inc sp");
6290 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6291 if (!regalloc_dry_run)
6292 _G.stack.pushed++;
6293 i++;
6296 if (i < size) // Both to save an instruction on the last byte, and to ensure we get the correct value as cached for hl.
6298 emit2 ("dec hl");
6299 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6303 if (swap_de)
6304 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
6306 freeAsmop (IC_LEFT (ic), 0);
6309 /* This is quite unfortunate */
6310 static void
6311 setArea (int inHome)
6314 static int lastArea = 0;
6316 if (_G.in_home != inHome) {
6317 if (inHome) {
6318 const char *sz = port->mem.code_name;
6319 port->mem.code_name = "HOME";
6320 emit2("!area", CODE_NAME);
6321 port->mem.code_name = sz;
6323 else
6324 emit2("!area", CODE_NAME); */
6325 _G.in_home = inHome;
6326 // }
6329 static bool
6330 isInHome (void)
6332 return _G.in_home;
6335 /** Emit the code for a register parameter
6337 static void genSend (const iCode *ic)
6339 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
6341 /* Caller saves, and this is the first push/send. */
6342 // Scan ahead until we find the function that we are pushing/sending parameters to.
6343 const iCode *walk;
6344 for (walk = ic->next; walk; walk = walk->next)
6346 if (walk->op == CALL || walk->op == PCALL)
6347 break;
6350 if (!_G.saves.saved && !regalloc_dry_run) // Cost is counted at CALL or PCALL instead
6351 _saveRegsForCall (walk, requiresHL (ic->left->aop) || ic->next->op != CALL, false);
6353 sym_link *ftype = IS_FUNCPTR (operandType (IC_LEFT (walk))) ? operandType (IC_LEFT (walk))->next : operandType (IC_LEFT (walk));
6354 asmop *argreg = aopArg (ftype, ic->argreg);
6356 wassert (argreg);
6358 // The register argument shall not overwrite a still-needed (i.e. as further parameter or function for the call) value.
6359 if (!aopSame (argreg, 0, ic->left->aop, 0, argreg->size))
6360 for (int i = 0; i < argreg->size; i++)
6361 if (!isRegDead (argreg->aopu.aop_reg[i]->rIdx, ic))
6362 for (iCode *walk2 = ic->next; walk2; walk2 = walk2->next)
6364 if (walk2->op != CALL && walk2->left && IS_ITEMP (walk2->left))
6365 UNIMPLEMENTED;
6367 if (walk2->op == CALL || walk2->op == PCALL)
6368 break;
6371 bool a_dead = isRegDead (A_IDX, ic);
6372 bool hl_dead = isPairDead (PAIR_HL, ic);
6373 bool de_dead = isPairDead (PAIR_DE, ic);
6375 for (iCode *walk2 = ic->prev; walk2 && walk2->op == SEND; walk2 = walk2->prev)
6377 asmop *warg = aopArg (ftype, walk2->argreg);
6378 wassert (warg);
6379 a_dead &= (warg->regs[A_IDX] < 0);
6380 hl_dead &= (warg->regs[L_IDX] < 0 && warg->regs[H_IDX] < 0);
6381 de_dead &= (warg->regs[E_IDX] < 0 && warg->regs[D_IDX] < 0);
6384 genMove (argreg, IC_LEFT (ic)->aop, a_dead, hl_dead, de_dead, true);
6386 for (int i = 0; i < IC_LEFT (ic)->aop->size; i++)
6387 if (!regalloc_dry_run)
6388 z80_regs_used_as_parms_in_calls_from_current_function[argreg->aopu.aop_reg[i]->rIdx] = true;
6390 freeAsmop (IC_LEFT (ic), NULL);
6393 static void
6394 genCall (const iCode *ic)
6396 sym_link *dtype = operandType (IC_LEFT (ic));
6397 sym_link *etype = getSpec (dtype);
6398 sym_link *ftype = IS_FUNCPTR (dtype) ? dtype->next : dtype;
6399 int i;
6400 int prestackadjust = 0;
6401 bool tailjump = false;
6403 for (i = 0; i < IYH_IDX + 1; i++)
6404 z80_regs_preserved_in_calls_from_current_function[i] |= ftype->funcAttrs.preserved_regs[i];
6406 _saveRegsForCall (ic, false, false);
6408 aopOp (IC_LEFT (ic), ic, false, false);
6410 const bool bigreturn = (getSize (ftype->next) > 4) || IS_STRUCT (ftype->next); // Return value of big type or returning struct or union.
6411 const bool SomethingReturned = IS_ITEMP (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->spildir) ||
6412 IS_TRUE_SYMOP (IC_RESULT (ic));
6414 bool a_not_parm = !z80IsParmInCall(ftype, "a");
6415 bool a_free = a_not_parm && ic->left->aop->regs[A_IDX] < 0;
6416 bool hl_not_parm = !z80IsParmInCall(ftype, "l") && !z80IsParmInCall(ftype, "h");
6417 bool hl_free = hl_not_parm && ic->left->aop->regs[L_IDX] < 0 && ic->left->aop->regs[H_IDX] < 0;
6418 bool de_not_parm = !z80IsParmInCall(ftype, "e") && !z80IsParmInCall(ftype, "d");
6419 bool de_free = de_not_parm && ic->left->aop->regs[E_IDX] < 0 && ic->left->aop->regs[D_IDX] < 0;
6420 bool bc_not_parm = !z80IsParmInCall(ftype, "b") && !z80IsParmInCall(ftype, "c");
6421 bool bc_free = bc_not_parm && ic->left->aop->regs[C_IDX] < 0 && ic->left->aop->regs[B_IDX] < 0;
6424 if (SomethingReturned && !bigreturn)
6425 aopOp (IC_RESULT (ic), ic, true, false);
6427 if (bigreturn)
6429 PAIR_ID pair;
6430 int fp_offset, sp_offset;
6432 if (ic->op == PCALL && IS_SM83 || !hl_free)
6433 _push (PAIR_HL);
6434 aopOp (IC_RESULT (ic), ic, true, false);
6435 wassert (IC_RESULT (ic)->aop->type == AOP_STK || IC_RESULT (ic)->aop->type == AOP_EXSTK);
6436 fp_offset =
6437 IC_RESULT (ic)->aop->aopu.aop_stk + (IC_RESULT (ic)->aop->aopu.aop_stk >
6438 0 ? _G.stack.param_offset : 0);
6439 sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
6440 pair = (ic->op == PCALL && !IS_SM83 && !IY_RESERVED) ? PAIR_IY : PAIR_HL;
6441 if (IS_SM83 && sp_offset <= 127 && sp_offset >= -128)
6443 emit2 ("!ldahlsp", sp_offset);
6444 cost (2, 12);
6446 else
6448 emit2 ("ld %s, !immedword", _pairs[pair].name, (unsigned)sp_offset);
6449 if (pair == PAIR_IY)
6450 cost2 (4, 14, 12, 8, 0, 6, 4, 4);
6451 else
6452 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6453 emit2 ("add %s, sp", _pairs[pair].name);
6454 if (pair == PAIR_IY)
6455 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
6456 else
6457 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
6459 if (ic->op == PCALL && IS_SM83 || !hl_free)
6461 if (de_free)
6463 emit3 (A_LD, ASMOP_E, ASMOP_L);
6464 emit3 (A_LD, ASMOP_D, ASMOP_H);
6465 _pop (PAIR_HL);
6466 pair = PAIR_DE;
6468 else
6470 wassert (bc_free);
6471 emit3 (A_LD, ASMOP_C, ASMOP_L);
6472 emit3 (A_LD, ASMOP_B, ASMOP_H);
6473 _pop (PAIR_HL);
6474 pair = PAIR_BC;
6477 emit2 ("push %s", _pairs[pair].name);
6478 if (pair == PAIR_IY)
6479 cost2 (2, 15, 13, 12, 0, 8, 4, 5);
6480 else
6481 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6482 if (!regalloc_dry_run)
6483 _G.stack.pushed += 2;
6484 freeAsmop (IC_RESULT (ic), 0);
6485 hl_free = false;
6488 // Check if we can do tail call optimization.
6489 else if (currFunc && !IFFUNC_ISISR (currFunc->type) &&
6490 !ic->parmBytes &&
6491 !_G.stack.pushedHL && !_G.stack.pushedBC && !_G.stack.pushedDE && !_G.stack.pushedIY && // If for some reason something got pushed, we don't have the return address in place.
6492 (!isFuncCalleeStackCleanup (currFunc->type) || !ic->parmEscapeAlive && ic->op == CALL && 0 /* todo: test and enable depending on optimization goal - as done for stm8 - for z80 and r3ka this will be slower and bigger than without tail call optimization, but it saves RAM */) &&
6493 !ic->localEscapeAlive &&
6494 !IFFUNC_ISBANKEDCALL (dtype) && !IFFUNC_ISZ88DK_SHORTCALL (ftype) &&
6495 (_G.omitFramePtr || IS_SM83))
6497 int limit = 16; // Avoid endless loops in the code putting us into an endless loop here.
6499 if (isFuncCalleeStackCleanup (currFunc->type))
6501 const bool caller_bigreturn = currFunc->type->next && (getSize (currFunc->type->next) > 4) || IS_STRUCT (currFunc->type->next);
6502 int caller_stackparmbytes = caller_bigreturn * 2;
6503 for (value *caller_arg = FUNC_ARGS(currFunc->type); caller_arg; caller_arg = caller_arg->next)
6505 wassert (caller_arg->sym);
6506 if (!SPEC_REGPARM (caller_arg->etype))
6507 caller_stackparmbytes += getSize (caller_arg->sym->type);
6509 prestackadjust += caller_stackparmbytes;
6512 for (const iCode *nic = ic->next; nic && --limit;)
6514 const symbol *targetlabel = 0;
6516 if (nic->op == LABEL)
6518 else if (nic->op == GOTO) // We dont have ebbi here, so we cant just use eBBWithEntryLabel (ebbi, ic->label). Search manually.
6519 targetlabel = IC_LABEL (nic);
6520 else if (nic->op == RETURN && (!IC_LEFT (nic) || SomethingReturned && IC_RESULT (ic)->key == IC_LEFT (nic)->key))
6521 targetlabel = returnLabel;
6522 else if (nic->op == ENDFUNCTION)
6524 if (OP_SYMBOL (IC_LEFT (nic))->stack <= (ic->op == PCALL ? 1 : (optimize.codeSize ? 1 : 2)) + IS_RAB * 120)
6526 prestackadjust = OP_SYMBOL (IC_LEFT (nic))->stack;
6527 tailjump = true;
6528 break;
6530 prestackadjust = 0;
6531 break;
6533 else
6535 prestackadjust = 0;
6536 break;
6539 if (targetlabel)
6541 const iCode *nnic = 0;
6542 for (nnic = nic->next; nnic; nnic = nnic->next)
6543 if (nnic->op == LABEL && IC_LABEL (nnic)->key == targetlabel->key)
6544 break;
6545 if (!nnic)
6546 for (nnic = nic->prev; nnic; nnic = nnic->prev)
6547 if (nnic->op == LABEL && IC_LABEL (nnic)->key == targetlabel->key)
6548 break;
6549 if (!nnic)
6551 prestackadjust = 0;
6552 tailjump = false;
6553 break;
6556 nic = nnic;
6558 else
6559 nic = nic->next;
6563 if (tailjump && SomethingReturned) // Explicitly check for matching registers, as otherwise calls between __sdcccall(1) and __z88dk_fastcall will go wrong.
6564 for (int i = 0; i < IC_RESULT (ic)->aop->size; i++)
6565 if (!aopInReg (aopRet (currFunc->type), 0, aopRet (ftype)->aopu.aop_reg[0]->rIdx))
6566 tailjump = false;
6568 const bool jump = tailjump || !ic->parmBytes && !bigreturn && ic->op != PCALL && !IFFUNC_ISBANKEDCALL (dtype) && !IFFUNC_ISZ88DK_SHORTCALL(ftype) && IFFUNC_ISNORETURN (ftype);
6570 if (ic->op == PCALL)
6572 if (IFFUNC_ISBANKEDCALL (dtype))
6574 werror (W_INDIR_BANKED);
6576 else if (IFFUNC_ISZ88DK_SHORTCALL (ftype))
6578 wassertl(0, "__z88dk_short_call via function pointer not implemented");
6581 if (isLitWord (IC_LEFT (ic)->aop))
6583 adjustStack (prestackadjust, a_free, bc_free, de_free, hl_free, false);
6584 emit2 (jump ? "jp %s" : "call %s", aopGetLitWordLong (IC_LEFT (ic)->aop, 0, FALSE));
6585 if (jump)
6586 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
6587 else
6588 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
6590 else if (getPairId (IC_LEFT (ic)->aop) != PAIR_IY && hl_free)
6592 spillPair (PAIR_HL);
6593 genMove (ASMOP_HL, IC_LEFT (ic)->aop, a_free, hl_free, de_free, true);
6594 adjustStack (prestackadjust, a_not_parm, bc_not_parm, de_not_parm, false, false);
6595 emit2 (jump ? "!jphl" : "call ___sdcc_call_hl");
6596 if (jump)
6597 cost2 (1, 4, 3, 4, 4, 8, 3, 1);
6598 else
6600 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
6601 // todo: add cycles spent in ___sdcc_call_hl here
6604 else if (!IS_SM83 && !IY_RESERVED && !z80IsParmInCall (ftype, "iy")) // Ensure that we don't access the stack via iy when reading IC_LEFT (ic).
6606 spillPair (PAIR_IY);
6607 if (IC_LEFT (ic)->aop->type == AOP_EXSTK) // Ensure that we don't directly overwrite iyl while accessing the stack via iy.
6609 _push (PAIR_HL);
6610 genMove (ASMOP_HL, IC_LEFT (ic)->aop, a_not_parm, true, de_not_parm, true);
6611 emit2 ("ex (sp), hl");
6612 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
6613 _pop (PAIR_IY);
6615 else
6616 genMove (ASMOP_IY, IC_LEFT (ic)->aop, a_not_parm, hl_not_parm, de_not_parm, true);
6617 adjustStack (prestackadjust, a_not_parm, bc_not_parm, de_not_parm, hl_not_parm, false);
6618 emit2 (jump ? "jp (iy)" : "call ___sdcc_call_iy");
6619 if (jump)
6620 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
6621 else
6623 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
6624 // todo: add cycles spent in ___sdcc_call_iy here
6627 else if (bc_not_parm && (ic->left->aop->regs[B_IDX] < 0 && ic->left->aop->regs[C_IDX] < 0 || de_free)) // Try bc, since it is the only 16-bit register guarateed to be free even for __z88dk_fastcall with --reserve-regs-iy
6629 wassert (!prestackadjust);
6630 wassert (IY_RESERVED || IS_SM83); // The peephole optimizer handles ret for purposes other than returning only for --reserve-regs-iy
6631 symbol *tlbl = 0;
6632 if (ic->left->aop->regs[B_IDX] >= 0 || ic->left->aop->regs[C_IDX] >= 0)
6634 wassert (de_free);
6635 if (!regalloc_dry_run)
6637 tlbl = newiTempLabel (NULL);
6638 emit2 ("ld de, !immed!tlabel", labelKey2num (tlbl->key));
6639 _push (PAIR_DE);
6641 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6643 else if (!regalloc_dry_run)
6645 if (!regalloc_dry_run)
6647 tlbl = newiTempLabel (NULL);
6648 emit2 ("ld bc, !immed!tlabel", labelKey2num (tlbl->key));
6649 _push (PAIR_BC);
6651 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6653 genMove (ASMOP_BC, IC_LEFT (ic)->aop, a_not_parm, hl_not_parm, de_not_parm, true);
6654 emit2 ("push bc");
6655 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6656 emit2 ("ret");
6657 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
6658 if (!regalloc_dry_run)
6659 _G.stack.pushed -= 2;
6660 if (tlbl)
6661 emitLabel (tlbl);
6663 else if (de_not_parm && (ic->left->aop->regs[D_IDX] < 0 && ic->left->aop->regs[E_IDX] < 0 || bc_free)) // Try de.
6665 wassert (!prestackadjust);
6666 wassert (IY_RESERVED || IS_SM83); // The peephole optimizer handles ret for purposes other than returning only for --reserve-regs-iy
6667 symbol *tlbl = 0;
6668 if (ic->left->aop->regs[D_IDX] >= 0 || ic->left->aop->regs[E_IDX] >= 0)
6670 wassert (bc_free);
6671 if (!regalloc_dry_run)
6673 tlbl = newiTempLabel (NULL);
6674 emit2 ("ld bc, !immed!tlabel", labelKey2num (tlbl->key));
6675 _push (PAIR_BC);
6677 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6679 else if (!regalloc_dry_run)
6681 if (!regalloc_dry_run)
6683 tlbl = newiTempLabel (NULL);
6684 emit2 ("ld de, !immed!tlabel", labelKey2num (tlbl->key));
6685 _push (PAIR_DE);
6687 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
6689 genMove (ASMOP_DE, IC_LEFT (ic)->aop, a_not_parm, hl_not_parm, true, true);
6690 emit2 ("push de");
6691 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6692 emit2 ("ret");
6693 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
6694 if (!regalloc_dry_run)
6695 _G.stack.pushed -= 2;
6696 if (tlbl)
6697 emitLabel (tlbl);
6699 else
6700 UNIMPLEMENTED;
6702 else
6704 /* make the call */
6705 if (IFFUNC_ISBANKEDCALL (dtype))
6707 wassert (!prestackadjust);
6709 char *name = OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name;
6710 /* there 3 types of banked call:
6711 legacy - only if --legacy-banking is specified
6712 a:bc - only for __z88dk_fastcall __banked functions
6713 e:hl - default (may have optimal bank switch routine) */
6714 if (z80_opts.legacyBanking)
6716 emit2 ("call ___sdcc_bcall");
6717 emit2 ("!dws", name);
6718 emit2 ("!dw !bankimmeds", name);
6719 regalloc_dry_run_cost += 7;
6721 else if (IFFUNC_ISZ88DK_FASTCALL (ftype))
6723 spillPair (PAIR_BC);
6724 emit2 ("ld a, !hashedbankimmeds", name);
6725 emit2 ("ld bc, !hashedstr", name);
6726 emit2 ("call ___sdcc_bcall_abc");
6727 regalloc_dry_run_cost += 8;
6729 else
6731 spillPair (PAIR_DE);
6732 spillPair (PAIR_HL);
6733 emit2 ("ld e, !hashedbankimmeds", name);
6734 emit2 ("ld hl, !hashedstr", name);
6735 emit2 ("call ___sdcc_bcall_ehl");
6736 regalloc_dry_run_cost += 8;
6739 else
6741 if (currFunc && isFuncCalleeStackCleanup (currFunc->type) && prestackadjust && !IFFUNC_ISNORETURN (ftype)) // Copy return value into correct location on stack for tail call optimization.
6743 wassert (0);
6744 /* todo: implement */
6747 adjustStack (prestackadjust, false, bc_free, de_free, hl_free, false);
6749 if (IS_LITERAL (etype))
6751 emit2 (jump ? "jp !constword" : "call !constword", ulFromVal (OP_VALUE (IC_LEFT (ic))));
6752 if (jump)
6753 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
6754 else
6755 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
6757 else if (IFFUNC_ISZ88DK_SHORTCALL(ftype))
6759 int rst = ftype->funcAttrs.z88dk_shortcall_rst;
6760 int value = ftype->funcAttrs.z88dk_shortcall_val;
6761 emit2 ("rst !constbyte", (unsigned)rst);
6762 cost2 (1, 11, 11, 8, 16, 0, 5, 4);
6763 if (value < 256)
6764 emit2 ("defb !constbyte\n", (unsigned)value);
6765 else
6766 emit2 ("defw !constword\n", (unsigned)value);
6767 regalloc_dry_run_cost_bytes += 2 + (value >= 256);
6769 else
6771 emit2 ("%s %s", jump ? "jp" : "call",
6772 (OP_SYMBOL (IC_LEFT (ic))->rname[0] ? OP_SYMBOL (IC_LEFT (ic))->rname : OP_SYMBOL (IC_LEFT (ic))->name));
6773 if (jump)
6774 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
6775 else
6776 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
6780 spillCached ();
6782 freeAsmop (IC_LEFT (ic), 0);
6784 _G.stack.pushed += prestackadjust;
6786 /* Mark the registers as restored. */
6787 _G.saves.saved = false;
6789 /* adjust the stack for parameters if required */
6790 if ((ic->parmBytes || bigreturn) && (IFFUNC_ISNORETURN (ftype) || isFuncCalleeStackCleanup (ftype)))
6792 if (!regalloc_dry_run)
6794 _G.stack.pushed -= (ic->parmBytes + bigreturn * 2);
6795 z80_symmParm_in_calls_from_current_function = false;
6798 else if ((ic->parmBytes || bigreturn))
6800 bool return_in_reg = SomethingReturned && !bigreturn;
6801 adjustStack (ic->parmBytes + bigreturn * 2,
6802 !return_in_reg || !aopRet (ftype) || aopRet (ftype)->regs[A_IDX] < 0 || aopRet (ftype)->regs[A_IDX] > IC_RESULT (ic)->aop->size,
6803 !return_in_reg || !aopRet (ftype) || (aopRet (ftype)->regs[C_IDX] < 0 || aopRet (ftype)->regs[C_IDX] > IC_RESULT (ic)->aop->size) && (aopRet (ftype)->regs[B_IDX] < 0 || aopRet (ftype)->regs[B_IDX] > IC_RESULT (ic)->aop->size),
6804 !return_in_reg || !aopRet (ftype) || (aopRet (ftype)->regs[E_IDX] < 0 || aopRet (ftype)->regs[E_IDX] > IC_RESULT (ic)->aop->size) && (aopRet (ftype)->regs[D_IDX] < 0 || aopRet (ftype)->regs[D_IDX] > IC_RESULT (ic)->aop->size),
6805 !return_in_reg || !aopRet (ftype) || (aopRet (ftype)->regs[L_IDX] < 0 || aopRet (ftype)->regs[L_IDX] > IC_RESULT (ic)->aop->size) && (aopRet (ftype)->regs[H_IDX] < 0 || aopRet (ftype)->regs[H_IDX] > IC_RESULT (ic)->aop->size),
6806 !IY_RESERVED);
6808 if (regalloc_dry_run)
6809 _G.stack.pushed += ic->parmBytes + bigreturn * 2;
6812 /* if we need assign a result value */
6813 if (SomethingReturned && !bigreturn)
6815 genMove (IC_RESULT (ic)->aop, aopRet (ftype), true, true, true, true);
6817 freeAsmop (IC_RESULT (ic), 0);
6820 spillCached ();
6822 restoreRegs (_G.stack.pushedIY, _G.stack.pushedDE, _G.stack.pushedBC, _G.stack.pushedHL, IC_RESULT (ic), ic);
6823 _G.stack.pushedIY = FALSE;
6824 _G.stack.pushedDE = FALSE;
6825 _G.stack.pushedBC = FALSE;
6826 _G.stack.pushedHL = FALSE;
6829 /*-----------------------------------------------------------------*/
6830 /* resultRemat - result is rematerializable */
6831 /*-----------------------------------------------------------------*/
6832 static int
6833 resultRemat (const iCode * ic)
6835 if (SKIP_IC (ic) || ic->op == IFX)
6836 return 0;
6838 if (IC_RESULT (ic) && IS_ITEMP (IC_RESULT (ic)))
6840 const symbol *sym = OP_SYMBOL_CONST (IC_RESULT (ic));
6841 if (sym->remat && !POINTER_SET (ic) && sym->isspilt)
6842 return 1;
6845 return 0;
6848 /*-----------------------------------------------------------------*/
6849 /* genFunction - generated code for function entry */
6850 /*-----------------------------------------------------------------*/
6851 static void
6852 genFunction (const iCode * ic)
6854 bool stackParm;
6856 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
6857 sym_link *ftype;
6859 bool bcInUse = FALSE;
6860 bool deInUse = FALSE;
6861 bool bigreturn;
6863 setArea (IFFUNC_NONBANKED (sym->type));
6864 _G.stack.pushed = 0;
6866 /* PENDING: Reset the receive offset as it
6867 doesn't seem to get reset anywhere else.
6869 _G.receiveOffset = 0;
6870 _G.stack.param_offset = sym->type->funcAttrs.z88dk_params_offset;
6872 /* Record the last function name for debugging. */
6873 _G.lastFunctionName = sym->rname;
6875 /* Create the function header */
6876 emit2 ("!functionheader", sym->name);
6878 emitDebug (z80_assignment_optimal ? "; Register assignment is optimal." : "; Register assignment might be sub-optimal.");
6879 emitDebug ("; Stack space usage: %d bytes.", sym->stack);
6881 if (IFFUNC_BANKED (sym->type))
6883 int bank_number = 0;
6884 for (int i = strlen (options.code_seg)-1; i >= 0; i--)
6886 if (!isdigit (options.code_seg[i]) && options.code_seg[i+1] != '\0')
6888 bank_number = atoi (&options.code_seg[i+1]);
6889 break;
6892 emit2("!bequ", sym->rname, bank_number);
6895 if (IS_STATIC (sym->etype))
6896 emit2 ("!functionlabeldef", sym->rname);
6897 else
6898 emit2 ("!globalfunctionlabeldef", sym->rname);
6900 if (!regalloc_dry_run)
6901 genLine.lineCurr->isLabel = 1;
6903 ftype = operandType (IC_LEFT (ic));
6905 if (IFFUNC_ISNAKED (ftype))
6907 emitDebug ("; naked function: no prologue.");
6908 return;
6911 /* if this is an interrupt service routine
6912 then save all potentially used registers. */
6913 if (IFFUNC_ISISR (sym->type))
6915 if (!IFFUNC_ISCRITICAL (sym->type))
6917 emit2 ("!ei");
6920 emit2 ("!pusha");
6922 else
6924 /* This is a non-ISR function.
6925 If critical function then turn interrupts off */
6926 if (IFFUNC_ISCRITICAL (sym->type))
6928 if (IS_SM83 || IS_RAB || IS_TLCS90)
6930 emit2 ("!di");
6932 else
6934 if (z80_opts.nmosZ80)
6935 emit2 ("call ___sdcc_critical_enter");
6936 else
6938 //get interrupt enable flag IFF2 into P/O
6939 emit2 ("ld a,i");
6940 //disable interrupts
6941 emit2 ("!di");
6943 //save P/O flag
6944 emit2 ("push af");
6945 _G.stack.param_offset += 2;
6950 if (z80_opts.calleeSavesBC)
6952 bcInUse = TRUE;
6955 /* Detect which registers are used. */
6956 if (IFFUNC_CALLEESAVES (sym->type) && sym->regsUsed)
6958 int i;
6959 for (i = 0; i < sym->regsUsed->size; i++)
6961 if (bitVectBitValue (sym->regsUsed, i))
6963 switch (i)
6965 case C_IDX:
6966 case B_IDX:
6967 bcInUse = TRUE;
6968 break;
6969 case D_IDX:
6970 case E_IDX:
6971 if (!IS_SM83)
6973 deInUse = true;
6975 else
6977 /* Other systems use DE as a temporary. */
6979 break;
6985 if (bcInUse)
6987 emit2 ("push bc");
6988 _G.stack.param_offset += 2;
6991 _G.calleeSaves.pushedBC = bcInUse;
6993 if (deInUse)
6995 emit2 ("push de");
6996 _G.stack.param_offset += 2;
6999 _G.calleeSaves.pushedDE = deInUse;
7001 /* adjust the stack for the function */
7002 // _G.stack.last = sym->stack;
7004 bigreturn = (getSize (ftype->next) > 4) || IS_STRUCT (ftype->next);
7005 _G.stack.param_offset += bigreturn * 2;
7007 stackParm = FALSE;
7008 for (sym = setFirstItem (istack->syms); sym; sym = setNextItem (istack->syms))
7010 if (sym->_isparm && !IS_REGPARM (sym->etype))
7012 stackParm = TRUE;
7013 break;
7016 sym = OP_SYMBOL (IC_LEFT (ic));
7018 _G.omitFramePtr = should_omit_frame_ptr;
7020 if (!IS_SM83 && !z80_opts.noOmitFramePtr && !stackParm && !sym->stack)
7022 if (!regalloc_dry_run)
7023 _G.omitFramePtr = true;
7025 else if (sym->stack)
7027 if (IS_EZ80_Z80 && !_G.omitFramePtr && -sym->stack > -128 && -sym->stack <= -3 && (z80IsParmInCall (sym->type, "l") || z80IsParmInCall (sym->type, "h")))
7029 emit2 ("push ix");
7030 cost (2, 4);
7031 emit2 ("ld ix, !immed%d", -sym->stack);
7032 cost (4, 4);
7033 emit2 ("add ix, sp");
7034 cost (2, 2);
7035 emit2 ("ld sp, ix");
7036 cost (2, 2);
7037 emit2 ("lea ix, ix, !immed%d", sym->stack);
7038 cost (3, 3);
7040 else
7042 if (!_G.omitFramePtr)
7043 emit2 ((optimize.codeSize && !z80IsParmInCall (sym->type, "l") && !z80IsParmInCall (sym->type, "h")) ? "!enters" : "!enter");
7044 if (IS_EZ80_Z80 && !_G.omitFramePtr && -sym->stack > -128 && -sym->stack <= -3 && !z80IsParmInCall (sym->type, "l") && !z80IsParmInCall (sym->type, "h"))
7046 emit2 ("lea hl, ix, !immed%d", -sym->stack);
7047 cost (3, 3);
7048 emit2 ("ld sp, hl");
7049 cost (1, 1);
7051 else
7052 adjustStack (-sym->stack, !z80IsParmInCall (sym->type, "a"), !z80IsParmInCall (sym->type, "c") && !z80IsParmInCall (sym->type, "v"), !z80IsParmInCall (sym->type, "e") && !z80IsParmInCall (sym->type, "d"), !z80IsParmInCall (sym->type, "l") && !z80IsParmInCall (sym->type, "h"), !IY_RESERVED);
7054 _G.stack.pushed = 0;
7056 else if (!_G.omitFramePtr)
7058 emit2 ((optimize.codeSize && !z80IsParmInCall (sym->type, "l") && !z80IsParmInCall (sym->type, "h")) ? "!enters" : "!enter"); // !enters might result in a function call to a helper function.
7061 _G.stack.offset = sym->stack;
7063 for (PAIR_ID pairId = 0; pairId < NUM_PAIRS; pairId++)
7064 spillPair (pairId);
7067 /*-----------------------------------------------------------------*/
7068 /* genEndFunction - generates epilogue for functions */
7069 /*-----------------------------------------------------------------*/
7070 static void
7071 genEndFunction (iCode *ic)
7073 symbol *sym = OP_SYMBOL (IC_LEFT (ic));
7074 /* __critical __interrupt without an interrupt number is the non-maskable interrupt */
7075 bool is_nmi = (IS_Z80 || IS_Z180 || IS_EZ80_Z80 || IS_Z80N || IS_R800) && IFFUNC_ISCRITICAL (sym->type) && FUNC_INTNO (sym->type) == INTNO_UNSPEC;
7076 bool bc_free = !aopRet (sym->type) || aopRet (sym->type)->regs[C_IDX] < 0 && aopRet (sym->type)->regs[B_IDX] < 0;
7077 bool de_free = !aopRet (sym->type) || aopRet (sym->type)->regs[E_IDX] < 0 && aopRet (sym->type)->regs[D_IDX] < 0;
7078 bool hl_free = !aopRet (sym->type) || aopRet (sym->type)->regs[L_IDX] < 0 && aopRet (sym->type)->regs[H_IDX] < 0;
7079 bool iy_free = !IY_RESERVED && (!aopRet (sym->type) || aopRet (sym->type)->regs[IYL_IDX] < 0 && aopRet (sym->type)->regs[IYH_IDX] < 0);
7081 wassert (!regalloc_dry_run);
7082 wassertl (!_G.stack.pushed, "Unbalanced stack.");
7084 if (IFFUNC_ISNAKED (sym->type) || IFFUNC_ISNORETURN (sym->type))
7086 emitDebug (IFFUNC_ISNAKED (sym->type) ? "; naked function: No epilogue." : "; _Noreturn function: No epilogue.");
7087 return;
7090 if (!regalloc_dry_run && IFFUNC_ISZ88DK_CALLEE (sym->type) && FUNC_HASVARARGS (sym->type))
7091 werror (E_Z88DK_CALLEE_VARARG); // We have no idea how many bytes on the stack we'd have to clean up.
7093 const bool bigreturn = (getSize (sym->type->next) > 4) || IS_STRUCT (sym->type->next);
7094 int stackparmbytes = bigreturn * 2;
7095 for (value *arg = FUNC_ARGS(sym->type); arg; arg = arg->next)
7097 wassert (arg->sym);
7098 int argsize = getSize (arg->sym->type);
7099 if (argsize == 1 && FUNC_ISSMALLC (sym->type)) // SmallC calling convention passes 8-bit stack arguments as 16 bit.
7100 argsize++;
7101 if (!SPEC_REGPARM (arg->etype))
7102 stackparmbytes += argsize;
7105 int poststackadjust = isFuncCalleeStackCleanup (sym->type) ? stackparmbytes : 0;
7107 if (poststackadjust && // Try to merge both stack adjustments.
7108 _G.omitFramePtr &&
7109 (IS_RAB && _G.stack.offset <= 255 || IS_TLCS90 && _G.stack.offset <= 127) &&
7110 (hl_free || iy_free) &&
7111 !_G.calleeSaves.pushedDE && !_G.calleeSaves.pushedBC &&
7112 !IFFUNC_ISISR (sym->type) && !IFFUNC_ISCRITICAL (sym->type))
7114 emit2 (hl_free ? "ld hl, %d (sp)" : "ld iy, %d (sp)", _G.stack.offset);
7115 if (hl_free)
7116 cost2 (2 + IS_TLCS90, 0, 0, 9, 0, 12, 0, 0);
7117 else
7118 cost2 (3, 0, 0, 11, 0, 12, 0, 0);
7119 adjustStack (_G.stack.offset + 2 + poststackadjust,
7120 !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0,
7121 bc_free,
7122 de_free,
7123 false,
7124 iy_free && hl_free);
7125 emit2 (hl_free ? "!jphl" : "jp (iy)");
7126 if (hl_free)
7127 cost2 (1 + IS_TLCS90, 4, 3, 4, 4, 8, 3, 1);
7128 else
7129 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
7130 goto done;
7132 else if (!IS_SM83 && !_G.omitFramePtr && sym->stack > (optimize.codeSize ? 2 : 1))
7134 emit2 ("ld sp, ix");
7135 cost2 (2, 10, 7, 4, 0, 6, 2, 2);
7137 else
7138 adjustStack (_G.stack.offset,
7139 !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0,
7140 bc_free,
7141 de_free,
7142 hl_free,
7143 iy_free);
7145 if(!IS_SM83 && !_G.omitFramePtr)
7147 emit2 ("pop ix");
7148 cost2 (2 - IS_TLCS90, 14, 12, 9, 0, 8, 4, 5);
7151 wassertl(regalloc_dry_run || !(isFuncCalleeStackCleanup (sym->type) && (_G.calleeSaves.pushedDE || _G.calleeSaves.pushedBC)), "Unimplemented __z88dk_callee support for calle-saved bc/de on callee side");
7152 if (_G.calleeSaves.pushedDE)
7154 emit2 ("pop de");
7155 cost2 (1, 10, 9, 7, 12, 8, 3, 4);
7156 _G.calleeSaves.pushedDE = FALSE;
7159 if (_G.calleeSaves.pushedBC)
7161 emit2 ("pop bc");
7162 cost2 (1, 10, 9, 7, 12, 8, 3, 4);
7163 _G.calleeSaves.pushedBC = FALSE;
7166 /* if this is an interrupt service routine
7167 then restore all potentially used registers. */
7168 if (IFFUNC_ISISR (sym->type))
7170 emit2 ("!popa");
7171 regalloc_dry_run_cost++;
7173 else
7175 /* This is a non-ISR function.
7176 If critical function then turn interrupts back on */
7177 if (IFFUNC_ISCRITICAL (sym->type))
7179 if (IS_SM83 || IS_TLCS90 || IS_RAB)
7180 emit2 ("!ei");
7181 else
7183 symbol *tlbl = newiTempLabel (NULL);
7184 //restore P/O flag
7185 if (aopRet (sym->type) && aopRet (sym->type)->regs[A_IDX] >= 0) // Preserve return value in a.
7187 wassert (!IS_SM83);
7188 emit2 ("ex (sp), hl");
7189 emit2 ("ld h, a");
7190 emit2 ("ex (sp), hl");
7192 emit2 ("pop af");
7193 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
7194 //don't enable interrupts as they were off before
7195 emit2 ("jp PO,!tlabel", labelKey2num (tlbl->key));
7196 emit2 ("!ei");
7197 emit2 ("!tlabeldef", labelKey2num (tlbl->key));
7198 genLine.lineCurr->isLabel = 1;
7203 if (poststackadjust)
7205 wassertl(regalloc_dry_run || !IFFUNC_ISBANKEDCALL (sym->type), "Unimplemented __banked __z88dk_callee support on callee side");
7206 wassertl(regalloc_dry_run || !IFFUNC_HASVARARGS (sym->type), "__z88dk_callee function may to have variable arguments");
7208 if (hl_free && !IFFUNC_ISISR (sym->type))
7210 _pop (PAIR_HL);
7211 // Parameters should be initialized, so reading them should be fine
7212 // we also exactly know which registers we can trash
7213 if (IS_SM83 && poststackadjust == 2 && (!aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0))
7214 { // return >8bit
7215 // This has priority since it shows notUsed that A is free
7216 // notUsed can't make assumptions about jp (hl)
7217 emit2 ("pop af");
7218 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
7220 else if (IS_SM83 && poststackadjust == 2 && bc_free)
7221 { // 8bit return
7222 emit2 ("pop bc");
7223 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
7225 else
7227 adjustStack (poststackadjust,
7228 !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0, bc_free, de_free, false, iy_free);
7230 emit2 ("!jphl");
7231 cost2 (1 + IS_TLCS90, 4, 3, 4, 4, 8, 3, 1);
7232 goto done;
7234 else if (!IS_SM83 && iy_free && !!IFFUNC_ISISR (sym->type))
7236 _pop (PAIR_IY);
7237 adjustStack (poststackadjust, !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0, bc_free, de_free, hl_free, false);
7238 emit2 ("jp (iy)");
7239 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
7240 goto done;
7242 else if (bc_free || de_free)
7244 _pop (bc_free ? PAIR_BC : PAIR_DE);
7245 adjustStack (poststackadjust, !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0, false, bc_free && de_free, false, false);
7246 _push (bc_free ? PAIR_BC : PAIR_DE);
7248 else // Do it the hard way: Copy return address on stack before stack pointer adjustment.
7250 if (poststackadjust == 1)
7252 _push (PAIR_HL);
7253 _push (PAIR_DE);
7254 emit2 ("ld hl, !immedword", 4u);
7255 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
7256 emit2 ("add hl, sp");
7257 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
7258 emit2 ("ld e, (hl)");
7259 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
7260 emit3w (A_INC, ASMOP_HL, 0);
7261 emit2 ("ld d, (hl)");
7262 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
7263 emit2 ("ld (hl), e");
7264 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7265 emit3w (A_INC, ASMOP_HL, 0);
7266 emit2 ("ld (hl), d");
7267 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7268 _pop (PAIR_DE);
7269 _pop (PAIR_HL);
7271 else if (IS_SM83)
7273 _push (PAIR_HL);
7274 _push (PAIR_DE);
7275 emit2 ("!ldahlsp", 4);
7276 regalloc_dry_run_cost += 2;
7277 emit2 ("ld e, (hl)");
7278 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
7279 emit3w (A_INC, ASMOP_HL, 0);
7280 emit2 ("ld d, (hl)");
7281 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
7282 emit2 ("ld hl, !immedword", (unsigned)(4 + poststackadjust));
7283 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
7284 emit2 ("add hl, sp");
7285 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
7286 emit2 ("ld (hl), e");
7287 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7288 emit3w (A_INC, ASMOP_HL, 0);
7289 emit2 ("ld (hl), d");
7290 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7291 _pop (PAIR_DE);
7292 _pop (PAIR_HL);
7294 else
7296 wassert (!IS_SM83);
7297 wassert (stackparmbytes != 1); // Avoid overwriting return address and hl.
7298 emit2 ("ex (sp), hl");
7299 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
7300 _push (PAIR_DE);
7301 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
7302 emit2 ("ld hl, !immedword", (unsigned)(2 + poststackadjust));
7303 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
7304 emit2 ("add hl, sp");
7305 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
7306 emit2 ("ld (hl), e");
7307 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7308 emit3w (A_INC, ASMOP_HL, 0);
7309 emit2 ("ld (hl), d");
7310 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
7311 _pop (PAIR_DE);
7312 emit2 ("ex (sp), hl");
7313 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
7316 adjustStack (poststackadjust,
7317 !aopRet (sym->type) || aopRet (sym->type)->regs[A_IDX] < 0,
7318 bc_free,
7319 de_free,
7320 false,
7321 iy_free);
7325 if (options.debug && currFunc)
7327 debugFile->writeEndFunction (currFunc, ic, 1);
7330 if (IFFUNC_ISISR (sym->type))
7332 if (is_nmi)
7334 emit2 ("retn");
7335 cost2 (2, 14, 12, 0, 0, 0, 6, 5);
7337 else if (IS_RAB)
7339 if (IFFUNC_ISCRITICAL (sym->type))
7341 emit2 ("!ei");
7342 cost2 (1, 4, 3, 0, 4, 2, 1, 1);
7344 emit2 ("ret");
7345 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
7347 else if (IS_SM83)
7349 emit2 (IFFUNC_ISCRITICAL (sym->type) ? "reti" : "ret");
7350 cost (1 + IFFUNC_ISCRITICAL (sym->type), 16);
7352 else
7354 if (IFFUNC_ISCRITICAL (sym->type) && !is_nmi)
7356 emit2 ("!ei");
7357 cost2 (1, 4, 3, 0, 4, 2, 1, 1);
7359 emit2 ("reti");
7360 cost2 (2, 14, 12, 12, 16, 14, 6, 5);
7363 else
7365 /* Both banked and non-banked just ret */
7366 emit2 ("ret");
7367 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
7370 done:
7371 _G.flushStatics = 1;
7372 _G.stack.pushed = 0;
7373 _G.stack.offset = 0;
7375 emitDebug (";\tTotal %s function size at codegen: %u bytes.", sym->name, (unsigned int)regalloc_dry_run_cost);
7378 /*-----------------------------------------------------------------*/
7379 /* genRet - generate code for return statement */
7380 /*-----------------------------------------------------------------*/
7381 static void
7382 genRet (const iCode *ic)
7384 /* Errk. This is a hack until I can figure out how
7385 to cause dehl to spill on a call */
7386 int size, offset = 0;
7388 /* if we have no return value then
7389 just generate the "ret" */
7390 if (!IC_LEFT (ic))
7391 goto jumpret;
7393 /* we have something to return then
7394 move the return value into place */
7395 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
7396 size = IC_LEFT (ic)->aop->size;
7398 if (size <= 4 && !IS_STRUCT (operandType (IC_LEFT (ic))))
7400 /* TODO: get this working with floats */
7401 if (IC_LEFT (ic)->aop->type == AOP_LIT && size == 4 && !IS_FLOAT (IC_LEFT (ic)->aop->aopu.aop_lit->type) &&
7402 (aopRet (currFunc->type) == ASMOP_DEHL || aopRet (currFunc->type) == ASMOP_HLDE))
7404 /* if we have to use two register pairs
7405 we can reuse values, this is also a prototype
7406 for the later literal on stack case */
7407 /* double load is slower, if one is immd, than 2B immd load,
7408 so we have to make sure both can be reused */
7409 bool first = false;
7410 unsigned char value[4];
7411 PAIR_ID regpairs[2];
7412 unsigned char offset[2] = {0, 2};
7413 unsigned long lit = ulFromVal (IC_LEFT (ic)->aop->aopu.aop_lit);
7414 value[0] = lit&0xff;
7415 lit>>=8;
7416 value[1] = lit&0xff;
7417 lit>>=8;
7418 value[2] = lit&0xff;
7419 lit>>=8;
7420 value[3] = lit&0xff;
7422 if(aopRet (currFunc->type) == ASMOP_HLDE)
7424 regpairs[0] = PAIR_DE;
7425 regpairs[1] = PAIR_HL;
7427 else
7429 regpairs[0] = PAIR_HL;
7430 regpairs[1] = PAIR_DE;
7433 /* swap if first pair can't hold the immd */
7434 if(value[0] == value[1] && value[2] != value[3])
7436 PAIR_ID tmpair = regpairs[0];
7437 regpairs[0] = regpairs[1];
7438 regpairs[1] = tmpair;
7440 unsigned char tmp = value[0];
7441 value[0] = value[2];
7442 value[2] = tmp;
7443 tmp = value[1];
7444 value[1] = value[3];
7445 value[3] = tmp;
7447 tmp = offset[0];
7448 offset[0] = offset[1];
7449 offset[1] = tmp;
7452 fetchPairLong (regpairs[0], IC_LEFT (ic)->aop, 0, offset[0]);
7453 if(value[2] == value[0])
7455 emit2 ("ld %s, %s", _pairs[regpairs[1]].l, _pairs[regpairs[0]].l);
7456 first = true;
7458 else if(value[2] == value[1])
7460 emit2 ("ld %s, %s", _pairs[regpairs[1]].l, _pairs[regpairs[0]].h);
7461 first = true;
7464 if(value[3] == value[0] && first == true)
7466 emit2 ("ld %s, %s", _pairs[regpairs[1]].h, _pairs[regpairs[0]].l);
7468 else if(value[3] == value[1] && first == true)
7470 emit2 ("ld %s, %s", _pairs[regpairs[1]].h, _pairs[regpairs[0]].h);
7472 else
7474 /* Makes previous loads redundant, which
7475 will be optimized by peep hole rules */
7476 fetchPairLong (regpairs[1], IC_LEFT (ic)->aop, 0, offset[1]);
7479 else if (size > 0) // SDCC supports GCC extension of returning void
7480 genMove (aopRet (currFunc->type), IC_LEFT (ic)->aop, true, true, true, true);
7482 else if (IC_LEFT (ic)->aop->type == AOP_LIT)
7484 unsigned long long lit = ullFromVal (IC_LEFT (ic)->aop->aopu.aop_lit);
7485 setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_SM83 ? 0 : 2));
7486 emit2 ("!ldahli");
7487 regalloc_dry_run_cost += 6;
7488 emit2 ("ld h, !*hl");
7489 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
7490 emit3 (A_LD, ASMOP_L, ASMOP_A);
7493 emit2 ("ld !*hl, !immedbyte", (unsigned)(lit & 0xffu));
7494 cost2 (2, 10, 9, 7, 12, 8, 3, 3);
7495 lit >>= 8;
7496 if (size > 1)
7497 emit3w (A_INC, ASMOP_HL, 0);
7499 while (--size);
7501 // gbz80 doesn't have have ldir. Rabbit 2000 to Rabbit 3000 (i.e. r2k and r2ka port) have an ldir wait state bug that affects copies between different types of memory.
7502 else if (!IS_SM83 && IC_LEFT (ic)->aop->type == AOP_STK || IC_LEFT (ic)->aop->type == AOP_EXSTK
7503 || (IC_LEFT (ic)->aop->type == AOP_DIR || IC_LEFT (ic)->aop->type == AOP_IY) && !(IS_R2K || IS_R2KA))
7505 setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_SM83 ? 0 : 2));
7506 emit2 ("ld e, !*hl");
7507 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
7508 emit3w (A_INC, ASMOP_HL, 0);
7509 emit2 ("ld d, !*hl");
7510 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
7511 if (IC_LEFT (ic)->aop->type == AOP_STK || IC_LEFT (ic)->aop->type == AOP_EXSTK)
7513 int sp_offset, fp_offset;
7514 fp_offset =
7515 IC_LEFT (ic)->aop->aopu.aop_stk + (IC_LEFT (ic)->aop->aopu.aop_stk >
7516 0 ? _G.stack.param_offset : 0);
7517 sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
7518 // TODO: find out if offset is okay
7519 emit2 ("!ldahlsp", sp_offset);
7520 spillPair (PAIR_HL);
7521 regalloc_dry_run_cost += 4;
7523 else
7524 fetchLitPair (PAIR_HL, IC_LEFT (ic)->aop, 0, true, false);
7525 emit2 ("ld bc, !immed%d", size);
7526 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
7527 emit2 ("ldir");
7528 cost2 (2, 21 * size - 5, 14 * size - 2, 7 * size - 1, 0, 18 * size - 4, 2 * size - 1, 4 * size);
7529 updatePair (PAIR_HL, size);
7531 else
7533 setupPairFromSP (PAIR_HL, _G.stack.offset + _G.stack.param_offset + _G.stack.pushed + (_G.omitFramePtr || IS_SM83 ? 0 : 2));
7534 emit2 ("ld c, !*hl");
7535 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
7536 emit3w (A_INC, ASMOP_HL, 0);
7537 emit2 ("ld b, !*hl");
7538 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
7539 updatePair (PAIR_HL, 1);
7542 cheapMove (ASMOP_A, 0, IC_LEFT (ic)->aop, offset++, true);
7543 emit2 ("ld !mems, a", "bc");
7544 cost2 (1 + IS_TLCS90, 7, 7, 7, 8, 6, 2, 2);
7545 if (size > 1)
7546 emit3w (A_INC, ASMOP_BC, 0);
7548 while (--size);
7550 freeAsmop (IC_LEFT (ic), NULL);
7552 jumpret:
7553 /* generate a jump to the return label
7554 if the next is not the return statement */
7555 if (!(ic->next && ic->next->op == LABEL && IC_LABEL (ic->next) == returnLabel))
7557 if (!regalloc_dry_run)
7558 emit2 ("jp !tlabel", labelKey2num (returnLabel->key));
7559 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
7563 /*-----------------------------------------------------------------*/
7564 /* genLabel - generates a label */
7565 /*-----------------------------------------------------------------*/
7566 static void
7567 genLabel (const iCode * ic)
7569 /* special case never generate */
7570 if (IC_LABEL (ic) == entryLabel)
7571 return;
7573 emitLabelSpill (IC_LABEL (ic));
7576 /*-----------------------------------------------------------------*/
7577 /* genGoto - generates a ljmp */
7578 /*-----------------------------------------------------------------*/
7579 static void
7580 genGoto (const iCode * ic)
7582 emit2 ("jp !tlabel", labelKey2num (IC_LABEL (ic)->key));
7585 /*-----------------------------------------------------------------*/
7586 /* genPlusIncr :- does addition with increment if possible */
7587 /*-----------------------------------------------------------------*/
7588 static bool
7589 genPlusIncr (const iCode *ic)
7591 unsigned int icount;
7592 unsigned int size = IC_RESULT (ic)->aop->size;
7593 PAIR_ID resultId = getPairId (IC_RESULT (ic)->aop);
7595 /* will try to generate an increment */
7596 /* if the right side is not a literal
7597 we cannot */
7598 if (IC_RIGHT (ic)->aop->type != AOP_LIT)
7599 return FALSE;
7601 icount = (unsigned int) ulFromVal (IC_RIGHT (ic)->aop->aopu.aop_lit);
7603 /* If result is a pair */
7604 if (resultId != PAIR_INVALID)
7606 bool delayed_move;
7607 if (isLitWord (IC_LEFT (ic)->aop))
7609 fetchLitPair (getPairId (IC_RESULT (ic)->aop), IC_LEFT (ic)->aop, icount, true, false);
7610 return TRUE;
7613 if (size == 2 && icount == 256 && ic->result->aop->type == AOP_REG && ic->left->aop->type == AOP_REG && ic->result->aop->aopu.aop_reg[0]->rIdx == ic->left->aop->aopu.aop_reg[0]->rIdx &&
7614 (HAS_IYL_INST || !aopInReg (ic->result->aop, 1, IYL_IDX) && !aopInReg (ic->result->aop, 1, IYH_IDX)))
7616 emit3_o (A_INC, ic->result->aop, 1, 0, 0);
7617 return true;
7620 if (IS_Z80N && resultId == getPairId (IC_LEFT (ic)->aop) && resultId != PAIR_IY && icount > 3 && icount < 256 && isRegDead (A_IDX, ic)) // Saves once cycle vs. add dd, nn below.
7622 cheapMove (ASMOP_A, 0, IC_RIGHT (ic)->aop, 0, true);
7623 emit2 ("add %s, a", getPairName (IC_RESULT (ic)->aop));
7624 cost (2, 8);
7625 return true;
7627 else if (icount == 255 && resultId != PAIR_IY)
7629 fetchPair (resultId, IC_LEFT (ic)->aop);
7630 emit3w (A_DEC, ic->result->aop, 0);
7631 emit3_o (A_INC, ic->result->aop, 1, 0, 0);
7632 return true;
7634 else if (icount == 257 && resultId != PAIR_IY)
7636 fetchPair (resultId, IC_LEFT (ic)->aop);
7637 emit3w (A_INC, ic->result->aop, 0);
7638 emit3_o (A_INC, ic->result->aop, 1, 0, 0);
7639 return true;
7641 else if (resultId == getPairId (ic->left->aop) &&
7642 (IS_Z80N && resultId != PAIR_IY && icount > 3 || IS_TLCS90 && (resultId == PAIR_HL || resultId == PAIR_IY) && icount > 2))
7644 emit2 ("add %s, !immed%s", getPairName (IC_RESULT (ic)->aop), aopGetLitWordLong (IC_RIGHT (ic)->aop, 0, false));
7645 cost2 (4 - IS_TLCS90, 16, 0, 0, 0, 6, 0, 0);
7646 return true;
7649 if (isPair (IC_LEFT (ic)->aop) && getPairId (IC_LEFT (ic)->aop) != PAIR_IY && resultId == PAIR_HL && icount > 3)
7651 if (getPairId (IC_LEFT (ic)->aop) == PAIR_HL)
7653 PAIR_ID freep = getDeadPairId (ic);
7654 if (freep != PAIR_INVALID)
7656 fetchPair (freep, IC_RIGHT (ic)->aop);
7657 emit2 ("add hl, %s", _pairs[freep].name);
7658 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
7659 return TRUE;
7662 else
7664 fetchPair (PAIR_HL, IC_RIGHT (ic)->aop);
7665 emit3w (A_ADD, ASMOP_HL, ic->left->aop);
7666 return true;
7669 if (icount > 5)
7670 return FALSE;
7671 /* Inc a pair */
7672 delayed_move = (getPairId (IC_RESULT (ic)->aop) == PAIR_IY && getPairId (IC_LEFT (ic)->aop) != PAIR_INVALID
7673 && isPairDead (getPairId (IC_LEFT (ic)->aop), ic));
7674 if (!sameRegs (IC_LEFT (ic)->aop, IC_RESULT (ic)->aop))
7676 if (icount > 3)
7677 return FALSE;
7678 if (!delayed_move)
7679 genMove (IC_RESULT (ic)->aop, IC_LEFT (ic)->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
7681 while (icount--)
7683 PAIR_ID pair = delayed_move ? getPairId (IC_LEFT (ic)->aop) : getPairId (IC_RESULT (ic)->aop);
7684 emit2 ("inc %s", _pairs[pair].name);
7685 if (pair == PAIR_IY)
7686 cost2 (2 - IS_TLCS90, 10, 7, 4, 0, 4, 2, 2);
7687 else
7688 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
7690 if (delayed_move)
7691 fetchPair (getPairId (IC_RESULT (ic)->aop), IC_LEFT (ic)->aop);
7692 return true;
7695 if (!IS_SM83 && isLitWord (IC_LEFT (ic)->aop) && size == 2 && isPairDead (PAIR_HL, ic))
7697 fetchLitPair (PAIR_HL, IC_LEFT (ic)->aop, icount, true, false);
7698 genMove (IC_RESULT (ic)->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
7699 return true;
7702 if (icount > 4) // Not worth it if the sequence of inc gets too long.
7703 return false;
7705 if (icount > 1 && size == 1 && aopInReg (IC_LEFT (ic)->aop, 0, A_IDX)) // add a, #n is cheaper than sequence of inc a.
7706 return false;
7708 if (size == 2 && getPairId (IC_LEFT (ic)->aop) != PAIR_INVALID && icount <= 3 && isPairDead (getPairId (IC_LEFT (ic)->aop), ic))
7710 while (icount--)
7711 emit3w (A_INC, ic->left->aop, 0);
7712 genMove (IC_RESULT (ic)->aop, IC_LEFT (ic)->aop, isRegDead (A_IDX, ic), isPairDead(PAIR_HL, ic), isPairDead(PAIR_DE, ic), true);
7713 return true;
7716 if (size == 2 && icount <= 2 && isPairDead (PAIR_HL, ic) && !IS_SM83 &&
7717 (IC_LEFT (ic)->aop->type == AOP_HL || IC_LEFT (ic)->aop->type == AOP_IY))
7719 genMove (ASMOP_HL, IC_LEFT (ic)->aop, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
7720 while (icount--)
7721 emit3w (A_INC, ASMOP_HL, 0);
7722 genMove (IC_RESULT (ic)->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
7723 return true;
7726 /* if increment 16 bits in register */
7727 if (sameRegs (IC_LEFT (ic)->aop, IC_RESULT (ic)->aop) && size > 1 && icount == 1
7728 && (HAS_IYL_INST || size == 2 && getPairId (IC_RESULT (ic)->aop) != PAIR_INVALID || size >= 2 && !aopInReg (IC_RESULT (ic)->aop, 0, IYL_IDX) && !aopInReg (IC_RESULT (ic)->aop, 0, IYH_IDX) && !aopInReg (IC_RESULT (ic)->aop, 1, IYL_IDX) && !aopInReg (IC_RESULT (ic)->aop, 1, IYH_IDX)))
7730 int offset = 0;
7731 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
7732 while (size--)
7734 if (offset)
7735 regalloc_dry_run_state_scale /= 256.0f; // Cycle cost contribution of upper byte additions is negligible
7736 if (aopIsLitVal (ic->result->aop, offset, size + 1, 0)) // Skip known leading zero result bytes.
7738 offset += size;
7739 size = 0;
7740 break;
7742 if (size == 1 && getPairId_o (IC_RESULT (ic)->aop, offset) != PAIR_INVALID)
7744 emit3w_o (A_INC, ic->result->aop, offset, 0, 0);
7745 size--;
7746 offset += 2;
7747 break;
7749 if (!HAS_IYL_INST && (aopInReg (IC_RESULT (ic)->aop, offset, IYL_IDX) || aopInReg (IC_RESULT (ic)->aop, offset, IYH_IDX)))
7750 UNIMPLEMENTED;
7751 else
7752 emit3_o (A_INC, IC_RESULT (ic)->aop, offset++, 0, 0);
7753 if (size)
7755 if (!regalloc_dry_run)
7756 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
7757 cost2 (3, 10, 9, 7, 16, 12, 4, 3); // Assume jump is taken (upper bytes are skipped).
7760 regalloc_dry_run_state_scale = 1.0f;
7761 if (!regalloc_dry_run)
7762 (IC_LEFT (ic)->aop->type == AOP_HL || IS_SM83
7763 && IC_LEFT (ic)->aop->type == AOP_STK) ? emitLabelSpill (tlbl) : emitLabel (tlbl);
7764 else if (IC_LEFT (ic)->aop->type == AOP_HL)
7765 spillCached ();
7766 return TRUE;
7769 /* if the sizes are greater than 1 then we cannot */
7770 if (IC_RESULT (ic)->aop->size > 1 || IC_LEFT (ic)->aop->size > 1)
7771 return FALSE;
7773 /* If the result is in a register then we can load then increment.
7775 if (IC_RESULT (ic)->aop->type == AOP_REG)
7777 cheapMove (IC_RESULT (ic)->aop, LSB, IC_LEFT (ic)->aop, LSB, true);
7778 while (icount--)
7779 if (!HAS_IYL_INST && (aopInReg (IC_RESULT (ic)->aop, 0, IYL_IDX) || aopInReg (IC_RESULT (ic)->aop, 0, IYH_IDX)))
7780 UNIMPLEMENTED;
7781 else
7782 emit3_o (A_INC, IC_RESULT (ic)->aop, 0, 0, 0);
7783 return TRUE;
7786 /* we can if the aops of the left & result match or
7787 if they are in registers and the registers are the
7788 same */
7789 if (sameRegs (IC_LEFT (ic)->aop, IC_RESULT (ic)->aop))
7791 while (icount--)
7792 emit3 (A_INC, IC_LEFT (ic)->aop, 0);
7793 return TRUE;
7796 return FALSE;
7799 /*-----------------------------------------------------------------*/
7800 /* outBitAcc - output a bit in acc */
7801 /*-----------------------------------------------------------------*/
7802 static void
7803 outBitAcc (operand * result)
7805 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
7806 /* if the result is a bit */
7807 if (result->aop->type == AOP_CRY)
7809 wassertl (0, "Tried to write A into a bit");
7811 else
7813 if (!regalloc_dry_run)
7815 emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
7816 emit2 ("ld a, !one");
7817 emitLabel (tlbl);
7819 // Assume that both values are equally likely.
7820 cost2 (3, 10, 7.5f, 3.5f, 14.0f, 11.0f, 3.5f, 3.0f);
7821 cost2 (1, 3.5f, 3.0f, 2.0f, 4.0f, 4.0f, 2.0f, 2.0f);
7822 outAcc (result);
7826 static bool
7827 couldDestroyCarry (const asmop *aop)
7829 if (aop)
7831 if (aop->type == AOP_EXSTK || aop->type == AOP_IY)
7833 return TRUE;
7836 return FALSE;
7839 static void
7840 shiftIntoPair (PAIR_ID id, asmop *aop)
7842 wassertl (!IS_SM83, "Not implemented for the SM83");
7844 emitDebug ("; Shift into pair");
7846 switch (id)
7848 case PAIR_HL:
7849 setupPair (PAIR_HL, aop, 0);
7850 break;
7851 case PAIR_DE:
7852 _push (PAIR_DE);
7853 setupPair (PAIR_IY, aop, 0);
7854 emit2 ("push iy");
7855 emit2 ("pop %s", _pairs[id].name);
7856 break;
7857 case PAIR_IY:
7858 setupPair (PAIR_IY, aop, 0);
7859 break;
7860 default:
7861 wassertl (0, "Internal error - hit default case");
7864 aop->type = AOP_PAIRPTR;
7865 aop->aopu.aop_pairId = id;
7866 _G.pairs[id].offset = 0;
7867 _G.pairs[id].last_type = aop->type;
7870 static void
7871 setupToPreserveCarry (asmop *result, asmop *left, asmop *right)
7873 wassert (left && right);
7875 if (!IS_SM83)
7877 if (couldDestroyCarry (right) && couldDestroyCarry (result))
7879 shiftIntoPair (PAIR_HL, right);
7880 /* check result again, in case right == result */
7881 if (couldDestroyCarry (result))
7883 if (couldDestroyCarry (left))
7884 shiftIntoPair (PAIR_DE, result);
7885 else
7886 shiftIntoPair (PAIR_IY, result);
7889 else if (couldDestroyCarry (right))
7891 if (getPairId (result) == PAIR_HL)
7892 _G.preserveCarry = TRUE;
7893 else
7894 shiftIntoPair (PAIR_HL, right);
7896 else if (couldDestroyCarry (result))
7898 shiftIntoPair (PAIR_HL, result);
7903 /*-----------------------------------------------------------------*/
7904 /* genPlus - generates code for addition */
7905 /*-----------------------------------------------------------------*/
7906 static void
7907 genPlus (iCode * ic)
7909 int size, i, offset = 0;
7910 signed char cached[2];
7911 bool premoved, started;
7912 asmop *leftop;
7913 asmop *rightop;
7914 symbol *tlbl = 0;
7916 /* special cases :- */
7918 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
7919 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
7920 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
7922 sym_link *resulttype = operandType (IC_RESULT (ic));
7923 unsigned topbytemask = (IS_BITINT (resulttype) && SPEC_USIGN (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
7924 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
7925 bool maskedtopbyte = (topbytemask != 0xff);
7927 /* Swap the left and right operands if:
7929 if literal, literal on the right or
7930 if left requires ACC or right is already
7931 in ACC */
7932 if ((IC_LEFT (ic)->aop->type == AOP_LIT) || (AOP_NEEDSACC (IC_RIGHT (ic))) || aopInReg (IC_RIGHT (ic)->aop, 0, A_IDX) ||
7933 IC_LEFT (ic)->aop->regs[A_IDX] < 0 && IC_RIGHT (ic)->aop->type == AOP_STL)
7935 operand *t = IC_RIGHT (ic);
7936 IC_RIGHT (ic) = IC_LEFT (ic);
7937 IC_LEFT (ic) = t;
7940 leftop = IC_LEFT (ic)->aop;
7941 rightop = IC_RIGHT (ic)->aop;
7943 /* if both left & right are in bit
7944 space */
7945 if (IC_LEFT (ic)->aop->type == AOP_CRY && IC_RIGHT (ic)->aop->type == AOP_CRY)
7947 /* Cant happen */
7948 wassertl (0, "Tried to add two bits");
7951 /* if left in bit space & right literal */
7952 if (IC_LEFT (ic)->aop->type == AOP_CRY && IC_RIGHT (ic)->aop->type == AOP_LIT)
7954 /* Can happen I guess */
7955 wassertl (0, "Tried to add a bit to a literal");
7958 /* if I can do an increment instead
7959 of add then GOOD for ME */
7960 if (!maskedtopbyte && genPlusIncr (ic))
7961 goto release;
7963 size = IC_RESULT (ic)->aop->size;
7965 /* Special case when left and right are constant */
7966 if (!maskedtopbyte && isPair (IC_RESULT (ic)->aop))
7968 char *left = Safe_strdup (aopGetLitWordLong (IC_LEFT (ic)->aop, 0, FALSE));
7969 const char *right = aopGetLitWordLong (IC_RIGHT (ic)->aop, 0, FALSE);
7971 if (IC_LEFT (ic)->aop->type == AOP_LIT && IC_RIGHT (ic)->aop->type == AOP_LIT && left && right)
7973 struct dbuf_s dbuf;
7975 /* It's a pair */
7976 /* PENDING: fix */
7977 dbuf_init (&dbuf, 128);
7978 dbuf_printf (&dbuf, "!immed(%s + %s)", left, right);
7979 Safe_free (left);
7980 emit2 ("ld %s, %s", getPairName (IC_RESULT (ic)->aop), dbuf_c_str (&dbuf));
7981 dbuf_destroy (&dbuf);
7982 if (getPairId (ic->result->aop) == PAIR_IY)
7983 cost2 (4, 14, 12, 8, 0, 6, 4, 4);
7984 else
7985 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
7986 goto release;
7988 Safe_free (left);
7991 // eZ80 has lea.
7992 if ((IS_TLCS90 || IS_EZ80_Z80) && !maskedtopbyte && isPair (IC_RESULT (ic)->aop) && getPairId (IC_LEFT (ic)->aop) == PAIR_IY && IC_RIGHT (ic)->aop->type == AOP_LIT)
7994 int lit = (int) ulFromVal (IC_RIGHT (ic)->aop->aopu.aop_lit);
7995 if (lit >= -128 && lit < 128)
7997 emit2 (IS_TLCS90 ? "lda %s, iy, !immed%d" : "lea %s, iy, !immed%d", _pairs[getPairId (IC_RESULT (ic)->aop)].name, lit);
7998 cost (3, IS_TLCS90 ? 10 : 3);
7999 spillPair (getPairId (IC_RESULT (ic)->aop));
8000 goto release;
8004 if (!maskedtopbyte && (isPair (IC_RIGHT (ic)->aop) || isPair (IC_LEFT (ic)->aop)) && getPairId (IC_RESULT (ic)->aop) == PAIR_HL)
8006 /* Fetch into HL then do the add */
8007 PAIR_ID left = getPairId (IC_LEFT (ic)->aop);
8008 PAIR_ID right = getPairId (IC_RIGHT (ic)->aop);
8010 spillPair (PAIR_HL);
8012 if (left == PAIR_HL && right != PAIR_INVALID && (IS_TLCS90 || right != PAIR_IY))
8014 emit3w (A_ADD, ASMOP_HL, ic->right->aop);
8015 goto release;
8017 else if (right == PAIR_HL && left != PAIR_INVALID && (IS_TLCS90 || left != PAIR_IY))
8019 emit3w (A_ADD, ASMOP_HL, ic->left->aop);
8020 goto release;
8022 else if (right != PAIR_INVALID && right != PAIR_HL && (IS_TLCS90 || right != PAIR_IY))
8024 genMove_o (ASMOP_HL, 0, ic->left->aop, 0, 2, isRegDead (A_IDX, ic), true, isRegDead (DE_IDX, ic) && right != PAIR_DE, isRegDead (IY_IDX, ic) && right != PAIR_IY, true);
8025 emit3w (A_ADD, ASMOP_HL, ic->right->aop);
8026 goto release;
8028 else if (left != PAIR_INVALID && left != PAIR_HL && (IS_TLCS90 || left != PAIR_IY))
8030 genMove_o (ASMOP_HL, 0, ic->right->aop, 0, 2, isRegDead (A_IDX, ic), true, isRegDead (DE_IDX, ic) && left != PAIR_DE, isRegDead (IY_IDX, ic) && left != PAIR_IY, true);
8031 emit3w (A_ADD, ASMOP_HL, ic->left->aop);
8032 goto release;
8034 else if (left == PAIR_HL && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)))
8036 PAIR_ID pair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
8037 asmop *raop = isPairDead (PAIR_DE, ic) ? ASMOP_DE : ASMOP_BC;
8038 genMove (raop, ic->right->aop, false, false, false, false);
8039 emit2 ("add hl, %s", _pairs[pair].name);
8040 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8041 goto release;
8043 else if (right == PAIR_HL && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)))
8045 PAIR_ID pair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
8046 asmop *raop = isPairDead (PAIR_DE, ic) ? ASMOP_DE : ASMOP_BC;
8047 genMove (raop, leftop, false, false, false, false);
8048 emit2 ("add hl, %s", _pairs[pair].name);
8049 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8050 goto release;
8052 else
8054 /* Can't do it */
8057 else if (!maskedtopbyte && size == 2 && getPairId (ic->result->aop) == PAIR_HL && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) &&
8058 (ic->right->aop->type == AOP_LIT || ic->right->aop->type == AOP_IMMD || ic->left->aop->type == AOP_IMMD && (ic->right->aop->type == AOP_HL || ic->right->aop->type == AOP_IY)))
8060 PAIR_ID extrapair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
8061 genMove (ASMOP_HL, ic->left->aop, isRegDead (A_IDX, ic), true, isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
8062 genMove (extrapair == PAIR_DE ? ASMOP_DE : ASMOP_BC, ic->right->aop, isRegDead (A_IDX, ic), false, isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
8063 emit2 ("add hl, %s", _pairs[extrapair].name);
8064 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8065 goto release;
8068 // Handle AOP_EXSTK conflict with hl here, since setupToPreserveCarry() would cause problems otherwise.
8069 if (!maskedtopbyte && IC_RESULT (ic)->aop->type == AOP_EXSTK && size <= 2 && (getPairId (IC_LEFT (ic)->aop) == PAIR_HL || getPairId (IC_RIGHT (ic)->aop) == PAIR_HL) &&
8070 (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) && isPairDead (PAIR_HL, ic))
8072 PAIR_ID extrapair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
8073 fetchPair (extrapair, getPairId (IC_LEFT (ic)->aop) == PAIR_HL ? IC_RIGHT (ic)->aop : IC_LEFT (ic)->aop);
8074 emit2 ("add hl, %s", _pairs[extrapair].name);
8075 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8076 spillPair (PAIR_HL);
8077 genMove (IC_RESULT (ic)->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
8078 goto release;
8080 else if (!maskedtopbyte && getPairId (IC_RESULT (ic)->aop) == PAIR_IY &&
8081 (getPairId (IC_LEFT (ic)->aop) == PAIR_HL && isPair (IC_RIGHT (ic)->aop) && getPairId (IC_RIGHT (ic)->aop) != PAIR_IY || getPairId (IC_RIGHT (ic)->aop) == PAIR_HL && isPair (IC_LEFT (ic)->aop) && getPairId (IC_LEFT (ic)->aop) != PAIR_IY) &&
8082 isPairDead (PAIR_HL, ic))
8084 PAIR_ID pair = (getPairId (IC_LEFT (ic)->aop) == PAIR_HL ? getPairId (IC_RIGHT (ic)->aop) : getPairId (IC_LEFT (ic)->aop));
8085 emit2 ("add hl, %s", _pairs[pair].name);
8086 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8087 _push (PAIR_HL);
8088 _pop (PAIR_IY);
8089 goto release;
8091 else if (!maskedtopbyte && getPairId (ic->result->aop) == PAIR_IY &&
8092 ic->left->aop->type != AOP_IY && ic->right->aop->type != AOP_IY)
8094 bool save_pair = FALSE;
8095 PAIR_ID pair;
8097 if (getPairId (IC_RIGHT (ic)->aop) == PAIR_IY || getPairId (IC_LEFT (ic)->aop) == PAIR_BC || getPairId (IC_LEFT (ic)->aop) == PAIR_DE ||
8098 ic->left->aop->regs[IYL_IDX] < 0 && ic->left->aop->regs[IYH_IDX] < 0 && (ic->right->aop->type == AOP_IMMD || ic->right->aop->type == AOP_LIT))
8100 operand *t = IC_RIGHT (ic);
8101 IC_RIGHT (ic) = IC_LEFT (ic);
8102 IC_LEFT (ic) = t;
8103 leftop = IC_LEFT (ic)->aop;
8104 rightop = IC_RIGHT (ic)->aop;
8106 pair = getPairId (IC_RIGHT (ic)->aop);
8107 if (pair != PAIR_BC && pair != PAIR_DE)
8109 if (IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX
8110 && (isRegDead (B_IDX, ic) || !isPairDead (PAIR_DE, ic)))
8111 pair = PAIR_BC;
8112 else if (IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX
8113 && (isRegDead (D_IDX, ic) || !isPairDead (PAIR_BC, ic)))
8114 pair = PAIR_DE;
8115 else
8116 pair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
8117 if (!isPairDead (pair, ic))
8118 save_pair = TRUE;
8120 genMove (ASMOP_IY, IC_LEFT (ic)->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
8121 if (save_pair)
8122 _push (pair);
8123 asmop *raop;
8124 switch (pair)
8126 case PAIR_BC:
8127 raop = ASMOP_BC;
8128 break;
8129 case PAIR_DE:
8130 raop = ASMOP_DE;
8131 break;
8132 case PAIR_IY:
8133 raop = ASMOP_IY;
8134 break;
8135 default:
8136 raop = 0;
8137 wassert (0);
8139 genMove (raop, ic->right->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
8140 emit2 ("add iy, %s", _pairs[pair].name);
8141 spillPair (PAIR_IY);
8142 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8143 if (save_pair)
8144 _pop (pair);
8145 goto release;
8148 /* sm83 special case:
8149 ld hl,sp+n trashes C so we can't afford to do it during an
8150 add with stack based variables. Worst case is:
8151 ld hl,sp+left
8152 ld a,(hl)
8153 ld hl,sp+right
8154 add (hl)
8155 ld hl,sp+result
8156 ld (hl),a
8157 ld hl,sp+left+1
8158 ld a,(hl)
8159 ld hl,sp+right+1
8160 adc (hl)
8161 ld hl,sp+result+1
8162 ld (hl),a
8163 So you can't afford to load up hl if either left, right, or result
8164 is on the stack (*sigh*) The alt is:
8165 ld hl,sp+left
8166 ld de,(hl)
8167 ld hl,sp+right
8168 ld hl,(hl)
8169 add hl,de
8170 ld hl,sp+result
8171 ld (hl),hl
8172 Combinations in here are:
8173 * If left or right are in bc then the loss is small - trap later
8174 * If the result is in bc then the loss is also small
8176 if (!maskedtopbyte && IS_SM83)
8178 if (IC_LEFT (ic)->aop->type == AOP_STK || IC_RIGHT (ic)->aop->type == AOP_STK || IC_RESULT (ic)->aop->type == AOP_STK)
8180 if ((IC_LEFT (ic)->aop->size == 2 ||
8181 IC_RIGHT (ic)->aop->size == 2) && (IC_LEFT (ic)->aop->size <= 2 && IC_RIGHT (ic)->aop->size <= 2 || size == 2))
8183 if (getPairId (IC_RIGHT (ic)->aop) == PAIR_BC || getPairId (IC_RIGHT (ic)->aop) == PAIR_DE && getPairId (IC_LEFT (ic)->aop) != PAIR_BC)
8185 /* Swap left and right */
8186 operand *t = IC_RIGHT (ic);
8187 IC_RIGHT (ic) = IC_LEFT (ic);
8188 IC_LEFT (ic) = t;
8189 leftop = IC_LEFT (ic)->aop;
8190 rightop = IC_RIGHT (ic)->aop;
8192 if (getPairId (IC_LEFT (ic)->aop) == PAIR_BC)
8194 fetchPair (PAIR_HL, IC_RIGHT (ic)->aop);
8195 emit3w (A_ADD, ASMOP_HL, ASMOP_BC);
8197 else
8199 if (!isPairDead (PAIR_DE, ic))
8200 _push (PAIR_DE);
8202 if (IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->size == 2 && IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->size == 2)
8204 const short dst[4] = { E_IDX, L_IDX, D_IDX, H_IDX };
8205 short src[4];
8206 if (IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX
8207 || IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX)
8209 src[0] = IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx;
8210 src[1] = IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx;
8211 src[2] = IC_RIGHT (ic)->aop->aopu.aop_reg[1]->rIdx;
8212 src[3] = IC_LEFT (ic)->aop->aopu.aop_reg[1]->rIdx;
8214 else
8216 src[1] = IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx;
8217 src[0] = IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx;
8218 src[3] = IC_RIGHT (ic)->aop->aopu.aop_reg[1]->rIdx;
8219 src[2] = IC_LEFT (ic)->aop->aopu.aop_reg[1]->rIdx;
8221 regMove (dst, src, 4, FALSE);
8223 else if (IC_RIGHT (ic)->aop->type == AOP_REG &&
8224 (IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX
8225 || IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == D_IDX || IC_RIGHT (ic)->aop->size == 2
8226 && (IC_RIGHT (ic)->aop->aopu.aop_reg[1]->rIdx == E_IDX
8227 || IC_RIGHT (ic)->aop->aopu.aop_reg[1]->rIdx == D_IDX)))
8229 fetchPair (PAIR_DE, IC_RIGHT (ic)->aop);
8230 fetchPair (PAIR_HL, IC_LEFT (ic)->aop);
8232 else
8234 fetchPair (PAIR_DE, IC_LEFT (ic)->aop);
8235 fetchPair (PAIR_HL, IC_RIGHT (ic)->aop);
8237 emit3w (A_ADD, ASMOP_HL, ASMOP_DE);
8239 if (maskedtopbyte)
8241 if (!isRegDead (A_IDX, ic))
8242 _push (PAIR_AF);
8243 emit3 (A_LD, ASMOP_A, ASMOP_H);
8244 emit2 ("and a, #0x%02x", topbytemask);
8245 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
8246 emit3 (A_LD, ASMOP_H, ASMOP_A);
8247 if (!isRegDead (A_IDX, ic))
8248 _pop (PAIR_AF);
8251 if (!isPairDead (PAIR_DE, ic))
8252 _pop (PAIR_DE);
8254 spillPair (PAIR_HL);
8255 genMove (IC_RESULT (ic)->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
8256 goto release;
8259 if (size == 4)
8261 /* Be paranoid on the GB with 4 byte variables due to how C
8262 can be trashed by lda hl,n(sp).
8264 _gbz80_emitAddSubLong (ic, TRUE);
8265 goto release;
8269 // Avoid overwriting operand in h or l when setupToPreserveCarry () loads hl - only necessary if carry is actually used during addition.
8270 premoved = FALSE;
8271 if (size > 1 &&
8272 !(size == 2 && isPair (leftop) && (rightop->type == AOP_LIT || rightop->type == AOP_IY)) && !(size == 2 && leftop->type == AOP_STL && isPairDead (PAIR_HL, ic))) // No need to setup if a single 16 bit addition is sufficient below.
8274 if (!couldDestroyCarry (leftop) && (couldDestroyCarry (rightop) || couldDestroyCarry (IC_RESULT (ic)->aop)))
8276 cheapMove (ASMOP_A, 0, leftop, offset, true);
8277 premoved = TRUE;
8280 if ((requiresHL (IC_RESULT (ic)->aop) && IC_RESULT (ic)->aop->type != AOP_REG || requiresHL (leftop) && leftop->type != AOP_REG || requiresHL (rightop) && rightop->type != AOP_REG) &&
8281 (leftop->regs[L_IDX] > 0 || leftop->regs[H_IDX] > 0 || rightop->regs[L_IDX] > 0 || rightop->regs[H_IDX] > 0))
8282 UNIMPLEMENTED;
8283 setupToPreserveCarry (IC_RESULT (ic)->aop, leftop, rightop);
8285 // 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.
8286 if (size == 1 && !aopInReg(leftop, 0, H_IDX) && !aopInReg(leftop, 0, L_IDX) && !aopInReg(rightop, 0, H_IDX) && !aopInReg(rightop, 0, L_IDX) && isPairDead (PAIR_HL, ic))
8288 if (couldDestroyCarry (IC_RESULT (ic)->aop) &&
8289 (IC_RESULT (ic)->aop == leftop || IC_RESULT (ic)->aop == rightop))
8290 shiftIntoPair (PAIR_HL, IC_RESULT (ic)->aop);
8291 else if (couldDestroyCarry (rightop))
8292 shiftIntoPair (PAIR_HL, rightop);
8295 cached[0] = -1;
8296 cached[1] = -1;
8298 for (i = 0, started = false; i < size;)
8300 bool maskedbyte = maskedtopbyte && (i + 1 == size);
8301 bool maskedword = maskedtopbyte && (i + 2 == size);
8303 const bool de_dead = isPairDead (PAIR_DE, ic) &&
8304 leftop->regs[E_IDX] <= i && leftop->regs[D_IDX] <= i &&
8305 rightop->regs[E_IDX] <= i && rightop->regs[D_IDX] <= i &&
8306 (IC_RESULT (ic)->aop->regs[E_IDX] < 0 || IC_RESULT (ic)->aop->regs[E_IDX] >= i) && (IC_RESULT (ic)->aop->regs[D_IDX] < 0 || IC_RESULT (ic)->aop->regs[D_IDX] >= i);
8307 const bool hl_dead = isPairDead (PAIR_HL, ic) &&
8308 leftop->regs[L_IDX] <= i && leftop->regs[H_IDX] <= i &&
8309 rightop->regs[L_IDX] <= i && rightop->regs[H_IDX] <= i &&
8310 (IC_RESULT (ic)->aop->regs[L_IDX] < 0 || IC_RESULT (ic)->aop->regs[L_IDX] >= i) && (IC_RESULT (ic)->aop->regs[H_IDX] < 0 || IC_RESULT (ic)->aop->regs[H_IDX] >= i);
8312 // Rematerialization of addresses on the stack.
8313 if (!maskedword && leftop->type == AOP_STL && !i && i + 1 < size && rightop->type == AOP_LIT && hl_dead)
8315 emit2 ("ld hl, !immed%d", spOffset (leftop->aopu.aop_stk) + (ulFromVal (rightop->aopu.aop_lit) & 0xffff));
8316 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
8317 emit2 ("add hl, sp");
8318 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8319 spillPair (PAIR_HL);
8320 started = true;
8321 genMove_o (IC_RESULT (ic)->aop, 0, ASMOP_HL, 0, 2, true, true, de_dead, false, i + 2 == size);
8322 i += 2;
8323 continue;
8325 else if (!maskedword && leftop->type == AOP_STL && !i && i + 1 < size && hl_dead && (size <= 2 || leftop->type != AOP_EXSTK /* (hl) would be pointed to result, overwritten by addition here */))
8327 PAIR_ID pair = getPairId (rightop);
8328 if (pair != PAIR_BC)
8329 pair = PAIR_DE;
8330 if (pair == PAIR_DE && !de_dead)
8331 _push (PAIR_DE);
8332 genMove (pair == PAIR_BC ? ASMOP_BC : ASMOP_DE, rightop, true, true, de_dead, false);
8333 genMove (ASMOP_HL, leftop, true, true, de_dead && pair != PAIR_DE, false);
8334 emit2 ("add hl, %s", _pairs[pair].name);
8335 spillPair (pair);
8336 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8337 started = true;
8338 if (pair == PAIR_DE && !de_dead)
8339 _pop (PAIR_DE);
8340 genMove_o (IC_RESULT (ic)->aop, 0, ASMOP_HL, 0, 2, true, true, de_dead, false, i + 2 == size);
8341 i += 2;
8342 continue;
8344 // Addition of interleaved pairs.
8345 else if (!maskedword && (!premoved || i) && leftop->size - i >= 2 && rightop->size - i >= 2 &&
8346 (aopInReg (IC_RESULT (ic)->aop, i, HL_IDX) || aopInReg (IC_RESULT (ic)->aop, i, IY_IDX) && !started))
8348 const bool iy = aopInReg (IC_RESULT (ic)->aop, i, IY_IDX);
8349 PAIR_ID pair = PAIR_INVALID;
8351 if (aopInReg (leftop, i, iy ? IYL_IDX : L_IDX) && aopInReg (rightop, i + 1, iy ? IYH_IDX : H_IDX))
8353 if (aopInReg (leftop, i + 1, D_IDX) && aopInReg (rightop, i, E_IDX))
8354 pair = PAIR_DE;
8355 else if (aopInReg (leftop, i + 1, B_IDX) && aopInReg (rightop, i, C_IDX))
8356 pair = PAIR_BC;
8358 else if (aopInReg (leftop, i + 1, iy ? IYH_IDX : H_IDX) && aopInReg (rightop, i, iy ? IYL_IDX : L_IDX))
8360 if (aopInReg (leftop, i, E_IDX) && aopInReg (rightop, i + 1, D_IDX))
8361 pair = PAIR_DE;
8362 else if (aopInReg (leftop, i, C_IDX) && aopInReg (rightop, i + 1, B_IDX))
8363 pair = PAIR_BC;
8366 if (pair != PAIR_INVALID)
8368 if (started)
8370 wassert (!iy);
8371 emit2 ("adc hl, %s", _pairs[pair].name);
8372 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8374 else
8376 emit2 (iy ? "add iy, %s" : "add hl, %s", _pairs[pair].name);
8377 started = true;
8378 if (pair == PAIR_IY)
8379 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8380 else
8381 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8383 i += 2;
8384 continue;
8388 if (!maskedword && (!premoved || i) && !started && leftop->size - i >= 2 && rightop->size - i >= 2 &&
8389 aopInReg (IC_RESULT (ic)->aop, i, IY_IDX) &&
8390 (aopInReg (leftop, i, IY_IDX) && (aopInReg (rightop, i, BC_IDX) || aopInReg (rightop, i, DE_IDX)) || aopInReg (rightop, i, IY_IDX) && (aopInReg (leftop, i, BC_IDX) || aopInReg (leftop, i, DE_IDX))))
8392 PAIR_ID pair = aopInReg(aopInReg (leftop, i, IY_IDX) ? rightop : leftop, i, BC_IDX) ? PAIR_BC : PAIR_DE;
8393 emit2 ("add iy, %s", _pairs[pair].name);
8394 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8395 started = true;
8396 i += 2;
8398 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && !i && isPair (rightop) && leftop->type == AOP_IMMD &&
8399 getPairId (rightop) != PAIR_HL && (IS_TLCS90 || getPairId (rightop) != PAIR_IY) &&
8400 isPairDead (PAIR_HL, ic))
8402 genMove_o (ASMOP_HL, 0, IC_LEFT (ic)->aop, i, 2, true, true, de_dead, true, true);
8403 emit3w (A_ADD, ASMOP_HL, ic->right->aop);
8404 started = true;
8405 spillPair (PAIR_HL);
8406 genMove_o (IC_RESULT (ic)->aop, i, ASMOP_HL, 0, 2, true, true, de_dead, true, true);
8407 i += 2;
8409 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && !i && isPair (leftop) && (rightop->type == AOP_LIT || rightop->type == AOP_IMMD) &&
8410 getPairId (leftop) != PAIR_HL && (IS_TLCS90 || getPairId (leftop) != PAIR_IY) &&
8411 isPairDead (PAIR_HL, ic))
8413 genMove_o (ASMOP_HL, 0, IC_RIGHT (ic)->aop, i, 2, true, true, de_dead, true, true);
8414 emit3w (A_ADD, ASMOP_HL, ic->left->aop);
8415 started = true;
8416 spillPair (PAIR_HL);
8417 genMove_o (IC_RESULT (ic)->aop, i, ASMOP_HL, 0, 2, true, true, de_dead, true, true);
8418 i += 2;
8420 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && !i && aopInReg (leftop, i, HL_IDX) &&
8421 isPair (rightop) && getPairId (rightop) != PAIR_HL && (IS_TLCS90 || getPairId (rightop) != PAIR_IY) &&
8422 isPairDead (PAIR_HL, ic))
8424 emit3w (A_ADD, ASMOP_HL, ic->right->aop);
8425 started = true;
8426 genMove_o (IC_RESULT (ic)->aop, i, ASMOP_HL, 0, 2, true, true, de_dead, true, true);
8427 i += 2;
8429 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && !i &&
8430 isPair (leftop) && getPairId (leftop) != PAIR_HL && (IS_TLCS90 || getPairId (leftop) != PAIR_IY) &&
8431 aopInReg (rightop, i, HL_IDX) && isPairDead (PAIR_HL, ic))
8433 emit3w (A_ADD, ASMOP_HL, ic->left->aop);
8434 started = true;
8435 genMove_o (IC_RESULT (ic)->aop, i, ASMOP_HL, 0, 2, true, true, de_dead, true, true);
8436 i += 2;
8438 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && aopInReg (ic->result->aop, i, HL_IDX) &&
8439 aopInReg (rightop, i, C_IDX) && isRegDead (B_IDX, ic))
8441 if (aopInReg (rightop, i + 1, H_IDX) || aopInReg (rightop, i + 1, L_IDX))
8443 cheapMove (ASMOP_B, 0, ic->right->aop, i + 1, true);
8444 genMove_o (ASMOP_HL, 0, ic->left->aop, i, 2, false, true, de_dead, false, !started);
8446 else
8448 bool de_free = de_dead && !aopInReg (ic->right->aop, i + 1, E_IDX) && !aopInReg (ic->right->aop, i + 1, D_IDX);
8449 genMove_o (ASMOP_HL, 0, ic->left->aop, i, 2, false, true, de_free, false, !started);
8450 cheapMove (ASMOP_B, 0, ic->right->aop, i + 1, true);
8452 emit3w (A_ADD, ASMOP_HL, ASMOP_BC);
8453 started = true;
8454 i += 2;
8456 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && aopInReg (IC_RESULT (ic)->aop, i, HL_IDX) &&
8457 aopInReg (rightop, i, E_IDX) && isRegDead (D_IDX, ic))
8459 if (aopInReg (rightop, i + 1, H_IDX) || aopInReg (rightop, i + 1, L_IDX))
8461 cheapMove (ASMOP_D, 0, IC_RIGHT (ic)->aop, i + 1, true);
8462 genMove_o (ASMOP_HL, 0, ic->left->aop, i, 2, false, true, de_dead, false, true);
8464 else
8466 bool de_free = de_dead && !aopInReg (ic->right->aop, i + 1, E_IDX) && !aopInReg (ic->right->aop, i + 1, D_IDX);
8467 genMove_o (ASMOP_HL, 0, ic->left->aop, i, 2, false, true, de_free, false, true);
8468 cheapMove (ASMOP_D, 0, ic->right->aop, i + 1, true);
8470 emit3w (A_ADD, ASMOP_HL, ASMOP_DE);
8471 started = true;
8472 i += 2;
8474 else if (!maskedword && (!premoved || i) && !started && i == size - 2 && aopInReg (IC_RESULT (ic)->aop, i, HL_IDX) &&
8475 aopInReg (leftop, i, E_IDX) && isRegDead (D_IDX, ic))
8477 if (aopInReg (leftop, i + 1, H_IDX) || aopInReg (leftop, i + 1, L_IDX))
8479 cheapMove (ASMOP_D, 0, IC_LEFT (ic)->aop, i + 1, true);
8480 fetchPairLong (PAIR_HL, IC_RIGHT (ic)->aop, 0, i);
8482 else
8484 fetchPairLong (PAIR_HL, IC_RIGHT (ic)->aop, 0, i);
8485 cheapMove (ASMOP_D, 0, IC_LEFT (ic)->aop, i + 1, true);
8487 emit3w (A_ADD, ASMOP_HL, ASMOP_DE);
8488 started = true;
8489 i += 2;
8491 // When adding a literal, the 16 bit addition results in smaller, faster code than two 8-bit additions.
8492 else if (!maskedword && (!premoved || i) && aopInReg (IC_RESULT (ic)->aop, i, HL_IDX) && aopInReg (leftop, i, HL_IDX) && (rightop->type == AOP_LIT && !aopIsLitVal (rightop, i, 1, 0) || rightop->type == AOP_IMMD))
8494 PAIR_ID pair = getFreePairId (ic);
8495 bool pair_alive;
8496 if (pair == PAIR_INVALID)
8497 pair = PAIR_DE;
8498 pair_alive = !isPairDead (pair, ic) ||
8499 IC_RESULT (ic)->aop->regs[_pairs[pair].l_idx] < i || IC_RESULT (ic)->aop->regs[_pairs[pair].h_idx] < i ||
8500 IC_LEFT (ic)->aop->regs[_pairs[pair].l_idx] >= i + 2 || IC_LEFT (ic)->aop->regs[_pairs[pair].h_idx] >= i + 2;
8501 if (pair_alive)
8502 _push (pair);
8503 fetchPairLong (pair, IC_RIGHT (ic)->aop, 0, i);
8504 if (started)
8506 emit2 ("adc hl, %s", _pairs[pair].name);
8507 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8509 else
8511 emit2 ("add hl, %s", _pairs[pair].name);
8512 started = TRUE;
8513 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8515 if (pair_alive)
8516 _pop (pair);
8517 i += 2;
8519 // When adding registers the 16 bit addition results in smaller, faster code than an 8-bit addition.
8520 else if (!maskedbyte && (!premoved || i) && i == size - 1 && isPairDead (PAIR_HL, ic) && aopInReg (IC_RESULT (ic)->aop, i, L_IDX)
8521 && (aopInReg (leftop, i, L_IDX) || aopInReg (rightop, i, L_IDX))
8522 && (aopInReg (leftop, i, C_IDX) || aopInReg (rightop, i, C_IDX) || aopInReg (leftop, i, E_IDX) || aopInReg (rightop, i, E_IDX)))
8524 PAIR_ID pair = (leftop->aopu.aop_reg[i]->rIdx == C_IDX
8525 || rightop->aopu.aop_reg[i]->rIdx == C_IDX) ? PAIR_BC : PAIR_DE;
8526 if (started)
8528 emit2 ("adc hl, %s", _pairs[pair].name);
8529 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8531 else
8533 emit2 ("add hl, %s", _pairs[pair].name);
8534 started = TRUE;
8535 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8537 i++;
8539 // When adding a literal, the 16 bit addition results in smaller, slower code than an 8-bit addition.
8540 else if (!maskedbyte && (!premoved || i) && optimize.codeSize && !started && i == size - 1 && isPairDead (PAIR_HL, ic)
8541 && rightop->type == AOP_LIT && aopInReg (IC_RESULT (ic)->aop, i, L_IDX) && aopInReg (leftop, i, L_IDX)
8542 && (isRegDead (C_IDX, ic) || isRegDead (E_IDX, ic)))
8544 PAIR_ID pair = !isRegDead (C_IDX, ic) ? PAIR_DE : PAIR_BC;
8545 emit2 ("ld %s, !immedbyte", _pairs[pair].l, (ulFromVal (IC_RIGHT (ic)->aop->aopu.aop_lit)) & 0xffu);
8546 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
8547 emit2 ("add hl, %s", _pairs[pair].name);
8548 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
8549 started = true;
8550 i++;
8552 // Skip over this byte.
8553 else if (!maskedbyte && !premoved && !started && (leftop->type == AOP_REG || IC_RESULT (ic)->aop->type == AOP_REG) && aopIsLitVal (rightop, i, 1, 0))
8555 cheapMove (IC_RESULT (ic)->aop, i, leftop, i, true);
8556 i++;
8558 // Conditional 16-bit inc.
8559 else if (!maskedword && i == size - 2 && started && aopIsLitVal (rightop, i, 2, 0) && (
8560 aopInReg (IC_RESULT (ic)->aop, i, BC_IDX) && aopInReg (leftop, i, BC_IDX) ||
8561 aopInReg (IC_RESULT (ic)->aop, i, DE_IDX) && aopInReg (leftop, i, DE_IDX) ||
8562 aopInReg (IC_RESULT (ic)->aop, i, HL_IDX) && aopInReg (leftop, i, HL_IDX) ||
8563 aopInReg (IC_RESULT (ic)->aop, i, IY_IDX) && aopInReg (leftop, i, IY_IDX)))
8565 if (!tlbl && !regalloc_dry_run)
8566 tlbl = newiTempLabel (0);
8568 if (!regalloc_dry_run)
8569 emit2 ("jp NC, !tlabel", labelKey2num (tlbl->key));
8570 cost2 (2 + IS_SM83, 12, 8, 5, 12, 12, 3, 3); // Assume branch is taken. 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.
8571 regalloc_dry_run_state_scale /= 256.0f; // Carry should be rare.
8572 emit3w_o (A_INC, leftop, i, 0, 0);
8573 i += 2;
8575 // Conditional 8-bit inc.
8576 else if (!maskedbyte && i == size - 1 && started && aopIsLitVal (rightop, i, 1, 0) &&
8577 !aopInReg (leftop, i, A_IDX) && // adc a, #0 is cheaper than conditional inc.
8578 (i < leftop->size &&
8579 leftop->type == AOP_REG && IC_RESULT (ic)->aop->type == AOP_REG &&
8580 leftop->aopu.aop_reg[i]->rIdx == IC_RESULT (ic)->aop->aopu.aop_reg[i]->rIdx &&
8581 (HAS_IYL_INST || leftop->aopu.aop_reg[i]->rIdx != IYL_IDX && leftop->aopu.aop_reg[i]->rIdx != IYH_IDX) ||
8582 leftop->type == AOP_STK && leftop == IC_RESULT (ic)->aop ||
8583 leftop->type == AOP_PAIRPTR && leftop->aopu.aop_pairId == PAIR_HL))
8585 if (!tlbl && !regalloc_dry_run)
8586 tlbl = newiTempLabel (0);
8587 if (!regalloc_dry_run)
8588 emit2 ("jp NC, !tlabel", labelKey2num (tlbl->key));
8589 cost2 (2 + IS_SM83, 12, 8, 5, 12, 12, 3, 3); // Assume branch is taken. 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.
8590 regalloc_dry_run_state_scale /= 256.0f; // Carry should be rare.
8591 emit3_o (A_INC, leftop, i, 0, 0);
8592 i++;
8594 else if (!started && !premoved && aopIsLitVal (leftop, i, 1, 0))
8596 cheapMove (ic->result->aop, i, rightop, i, true);
8597 i++;
8599 else
8601 if (!HAS_IYL_INST && (aopInReg (rightop, i, IYL_IDX) || aopInReg (rightop, i, IYH_IDX)))
8602 if (!premoved && !aopInReg (leftop, i, IYL_IDX) && !aopInReg (leftop, i, IYL_IDX))
8604 operand *t = IC_RIGHT (ic);
8605 IC_RIGHT (ic) = IC_LEFT (ic);
8606 IC_LEFT (ic) = t;
8607 leftop = IC_LEFT (ic)->aop;
8608 rightop = IC_RIGHT (ic)->aop;
8610 else // Can't handle both sides in iy.
8611 UNIMPLEMENTED;
8612 else if (rightop->type == AOP_STL && i < 2) // can't handle rematerialized stack location on the right efficiently.
8614 operand *t = IC_RIGHT (ic);
8615 IC_RIGHT (ic) = IC_LEFT (ic);
8616 IC_LEFT (ic) = t;
8617 leftop = IC_LEFT (ic)->aop;
8618 rightop = IC_RIGHT (ic)->aop;
8621 if (aopInReg (rightop, i, A_IDX) && !aopInReg (leftop, i, A_IDX)) // Make sure we don't overwrite the other operand.
8622 UNIMPLEMENTED;
8623 else if (!premoved)
8624 cheapMove (ASMOP_A, 0, leftop, i, true);
8625 else
8626 premoved = FALSE;
8628 if (!started && aopIsLitVal (rightop, i, 1, 0))
8629 ; // Skip over this byte.
8630 // 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.
8631 else if (!started && i == size - 1 && (aopIsLitVal (rightop, i, 1, 1) || aopIsLitVal (rightop, i, 1, 255)))
8633 emit3 (aopIsLitVal (rightop, i, 1, 1) ? A_INC : A_DEC, ASMOP_A, 0);
8634 started = true;
8636 else if (rightop->type == AOP_STL && i < 2)
8638 _push (PAIR_HL);
8639 genMove (ASMOP_HL, rightop, false, true, false, false);
8640 emit3 (started ? A_ADC : A_ADD, ASMOP_A, i ? ASMOP_H : ASMOP_L);
8641 started = true;
8642 _pop (PAIR_HL);
8644 else if (!HAS_IYL_INST && (aopInReg (rightop, i, IYL_IDX) || aopInReg (rightop, i, IYH_IDX)))
8645 UNIMPLEMENTED;
8646 else
8648 emit3_o (started ? A_ADC : A_ADD, ASMOP_A, 0, rightop, i);
8649 started = true;
8651 if (maskedbyte)
8653 emit2 ("and a, #0x%02x", topbytemask);
8654 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
8657 _G.preserveCarry = (i != size - 1);
8658 if (size &&
8659 (requiresHL (rightop) && rightop->size > i + 1 && rightop->type != AOP_REG || (requiresHL (leftop) && leftop->size > i + 1)
8660 && leftop->type != AOP_REG) && IC_RESULT (ic)->aop->type == AOP_REG
8661 && (IC_RESULT (ic)->aop->aopu.aop_reg[i]->rIdx == L_IDX
8662 || IC_RESULT (ic)->aop->aopu.aop_reg[i]->rIdx == H_IDX))
8664 wassert (cached[0] == -1 || cached[1] == -1);
8665 cached[cached[0] == -1 ? 0 : 1] = offset++;
8666 _push (PAIR_AF);
8668 // Avoid overwriting still-needed operand in h or l.
8669 else if (requiresHL (IC_RESULT (ic)->aop) && IC_RESULT (ic)->aop->type != AOP_REG && (IC_RESULT (ic)->aop->type == AOP_EXSTK || IS_SM83 || IC_RESULT (ic)->aop->type == AOP_PAIRPTR) &&
8670 (!isPairDead(PAIR_HL, ic) || i + 1 < size && IC_LEFT(ic)->aop->regs[L_IDX] > i || i + 1 < size && IC_LEFT(ic)->aop->regs[H_IDX] > i || i + 1 < size && IC_RIGHT(ic)->aop->regs[L_IDX] > i || i + 1 < size && IC_RIGHT(ic)->aop->regs[H_IDX] > i))
8672 _push (PAIR_HL);
8673 cheapMove (IC_RESULT (ic)->aop, i, ASMOP_A, 0, true);
8674 _pop (PAIR_HL);
8676 else
8677 cheapMove (IC_RESULT (ic)->aop, i, ASMOP_A, 0, true);
8678 i++;
8681 _G.preserveCarry = false;
8683 regalloc_dry_run_state_scale = 1.0f;
8684 if (tlbl)
8685 emitLabel (tlbl);
8687 for (size = 1; size >= 0; size--)
8688 if (cached[size] != -1)
8690 if (IC_RESULT (ic)->aop->regs[A_IDX] >= 0 && IC_RESULT (ic)->aop->regs[A_IDX] != size) // Don't overwrite still-needed a below.
8691 UNIMPLEMENTED;
8692 _pop (PAIR_AF);
8693 cheapMove (IC_RESULT (ic)->aop, cached[size], ASMOP_A, 0, true);
8696 release:
8697 _G.preserveCarry = FALSE;
8698 freeAsmop (IC_LEFT (ic), NULL);
8699 freeAsmop (IC_RIGHT (ic), NULL);
8700 freeAsmop (IC_RESULT (ic), NULL);
8703 /*-----------------------------------------------------------------*/
8704 /* genSubDec :- does subtraction with decrement if possible */
8705 /*-----------------------------------------------------------------*/
8706 static bool
8707 genMinusDec (const iCode *ic, asmop *result, asmop *left, asmop *right)
8709 unsigned int icount;
8710 unsigned int size = IC_RESULT (ic)->aop->size;
8712 /* will try to generate a decrement */
8713 /* if the right side is not a literal we cannot */
8714 if (right->type != AOP_LIT)
8715 return false;
8717 /* if the literal value of the right hand side
8718 is greater than 4 then it is not worth it */
8719 if ((icount = (unsigned int) ulFromVal (right->aopu.aop_lit)) > 2)
8720 return false;
8721 /* if decrement 16 bits in register */
8722 if (sameRegs (left, result) && (size > 1) && isPair (result))
8724 while (icount--)
8726 emit2 ("dec %s", getPairName (result));
8727 if (getPairId (result) == PAIR_IY)
8728 cost2 (2, 10, 7, 4, 0, 4, 2, 2);
8729 else
8730 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
8732 return true;
8735 /* If result is a pair */
8736 if (isPair (IC_RESULT (ic)->aop))
8738 fetchPair (getPairId (result), left);
8739 while (icount--)
8741 if (!regalloc_dry_run)
8742 emit2 ("dec %s", getPairName (result));
8743 if (getPairId (result) == PAIR_IY)
8744 cost2 (2, 10, 7, 4, 0, 4, 2, 2);
8745 else
8746 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
8748 return true;
8751 /* if decrement 16 bits in register */
8752 if (sameRegs (left, result) && size == 2 && isPairDead (_getTempPairId (), ic) && !(requiresHL (left) && _getTempPairId () == PAIR_HL))
8754 fetchPair (_getTempPairId (), left);
8756 while (icount--)
8758 if (!regalloc_dry_run)
8759 emit2 ("dec %s", _getTempPairName ());
8760 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
8763 commitPair (result, _getTempPairId (), ic, false);
8765 return true;
8769 /* if the sizes are greater than 1 then we cannot */
8770 if (result->size > 1 || left->size > 1)
8771 return false;
8773 /* we can if the aops of the left & result match or if they are in
8774 registers and the registers are the same */
8775 if (sameRegs (left, result))
8777 while (icount--)
8778 emit3 (A_DEC, result, 0);
8779 return true;
8782 if (result->type == AOP_REG)
8784 cheapMove (result, 0, left, 0, true);
8785 while (icount--)
8786 emit3 (A_DEC, result, 0);
8787 return true;
8790 return false;
8793 /*-----------------------------------------------------------------*/
8794 /* genSub - generates code for subtraction */
8795 /*-----------------------------------------------------------------*/
8796 static void
8797 genSub (const iCode *ic, asmop *result, asmop *left, asmop *right)
8799 int size, offset = 0;
8800 unsigned long long lit = 0L;
8802 sym_link *resulttype = operandType (IC_RESULT (ic));
8803 unsigned topbytemask = (IS_BITINT (resulttype) && SPEC_USIGN (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
8804 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
8805 bool maskedtopbyte = (topbytemask != 0xff);
8807 /* special cases :- */
8808 /* if both left & right are in bit space */
8809 if (left->type == AOP_CRY && right->type == AOP_CRY)
8811 wassertl (0, "Tried to subtract two bits");
8812 return;
8815 /* if I can do an decrement instead of subtract then GOOD for ME */
8816 if (!maskedtopbyte && genMinusDec (ic, result, left, right) == TRUE)
8817 return;
8819 size = IC_RESULT (ic)->aop->size;
8821 if (right->type == AOP_LIT)
8823 lit = ullFromVal (right->aopu.aop_lit);
8824 lit = -(long long) lit;
8827 /* Same logic as genPlus */
8828 if (!maskedtopbyte && IS_SM83)
8830 if (left->type == AOP_STK || right->type == AOP_STK || result->type == AOP_STK)
8832 if ((left->size == 2 ||
8833 right->size == 2) && (left->size <= 2 && right->size <= 2))
8835 PAIR_ID leftp = getPairId (left);
8836 PAIR_ID rightp = getPairId (right);
8838 if (leftp == PAIR_INVALID && rightp == PAIR_INVALID)
8840 leftp = PAIR_DE;
8841 rightp = PAIR_HL;
8843 else if (rightp == PAIR_INVALID)
8844 rightp = PAIR_DE;
8845 else if (leftp == PAIR_INVALID)
8846 leftp = PAIR_DE;
8848 fetchPair (leftp, left);
8849 /* Order is important. Right may be HL */
8850 fetchPair (rightp, right);
8852 emit2 ("ld a, %s", _pairs[leftp].l);
8853 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
8854 emit2 ("sub a, %s", _pairs[rightp].l);
8855 cost2 (1 + IS_TLCS90, 4, 4, 2, 4, 4, 1, 1);
8856 emit3 (A_LD, ASMOP_E, ASMOP_A);
8857 emit2 ("ld a, %s", _pairs[leftp].h);
8858 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
8859 emit2 ("sbc a, %s", _pairs[rightp].h);
8860 cost2 (1 + IS_TLCS90, 4, 4, 2, 4, 4, 1, 1);
8862 if (IC_RESULT (ic)->aop->size > 1)
8863 cheapMove (IC_RESULT (ic)->aop, 1, ASMOP_A, 0, true);
8864 cheapMove (IC_RESULT (ic)->aop, 0, ASMOP_E, 0, true);
8865 return;
8868 if (size == 4)
8870 /* Be paranoid on the GB with 4 byte variables due to how C
8871 can be trashed by lda hl,n(sp).
8873 _gbz80_emitAddSubLongLong (ic, left, right, FALSE);
8874 return;
8878 if ((requiresHL (result) && result->type != AOP_REG || requiresHL (left) && left->type != AOP_REG || requiresHL (right) && right->type != AOP_REG) &&
8879 (left->regs[L_IDX] > 0 || left->regs[H_IDX] > 0 || right->regs[L_IDX] > 0 || right->regs[H_IDX] > 0))
8880 UNIMPLEMENTED;
8881 setupToPreserveCarry (result, left, right);
8883 /* if literal right, add a, #-lit, else normal subb */
8884 while (size)
8886 bool maskedbyte = maskedtopbyte && (size == 1);
8887 bool maskedword = maskedtopbyte && (size == 2);
8889 if (!IS_SM83 && !maskedword && size >= 2 &&
8890 isPairDead (PAIR_HL, ic) &&
8891 (aopInReg (result, offset, HL_IDX) || aopInReg (result, offset, DE_IDX) || IS_RAB && result->type == AOP_STK) &&
8892 (result->regs[L_IDX] < 0 || result->regs[L_IDX] >= offset) && (result->regs[H_IDX] < 0 || result->regs[H_IDX] >= offset) &&
8893 (aopInReg (left, offset, HL_IDX) || (left->type == AOP_LIT || left->type == AOP_IY) && right->regs[L_IDX] < offset && right->regs[H_IDX] < offset) &&
8894 (aopInReg (right, offset, BC_IDX) || aopInReg (right, offset, DE_IDX) || ((right->type == AOP_IY || right->type == AOP_HL || IS_RAB && right->type == AOP_STK) && (getFreePairId (ic) == PAIR_DE || getFreePairId (ic) == PAIR_BC))))
8896 PAIR_ID rightpair;
8898 bool a_dead = isRegDead (A_IDX, ic) && (result->regs[A_IDX] < 0 || result->regs[A_IDX] >= offset);
8900 if (getPartPairId (right, offset) == PAIR_INVALID)
8902 rightpair = getFreePairId (ic);
8903 genMove_o (rightpair == PAIR_DE ? ASMOP_DE : ASMOP_BC, 0, right, offset, 2, a_dead, !aopInReg (left, offset, HL_IDX), false, true, !offset);
8905 else
8906 rightpair = getPartPairId (right, offset);
8907 if (!aopInReg (left, offset, HL_IDX))
8908 genMove_o (ASMOP_HL, 0, left, offset, 2, a_dead, true, false, true, !offset);
8910 if (!offset)
8911 emit3 (A_CP, ASMOP_A, ASMOP_A);
8912 emit2 ("sbc hl, %s", _pairs[rightpair].name);
8913 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8914 spillPair (PAIR_HL);
8915 genMove_o (result, offset, ASMOP_HL, 0, 2, a_dead, true, false, true, size <= 2);
8916 offset += 2;
8917 size -= 2;
8918 _G.preserveCarry = !!size;
8919 continue;
8922 bool l_dead = !(!isRegDead (L_IDX, ic) || left->regs[L_IDX] > offset || right->regs[L_IDX] > offset || result->regs[L_IDX] >= 0 && result->regs[L_IDX] < offset);
8923 bool h_dead = !(!isRegDead (H_IDX, ic) || left->regs[H_IDX] > offset || right->regs[H_IDX] > offset || result->regs[H_IDX] >= 0 && result->regs[H_IDX] < offset);
8924 bool hl_dead = l_dead && h_dead;
8925 bool pushed_hl = false;
8927 if (right->type == AOP_SFR) // Right operand needs to go through a
8929 asmop *tmpaop;
8931 if (aopInReg (left, offset, H_IDX))
8932 tmpaop = ASMOP_L;
8933 else if (aopInReg (left, offset, L_IDX))
8934 tmpaop = ASMOP_H;
8935 else if (!l_dead && h_dead)
8936 tmpaop = ASMOP_H;
8937 else
8938 tmpaop = ASMOP_L;
8940 bool tmpaop_dead = aopInReg (tmpaop, 0, L_IDX) ? l_dead : h_dead;
8941 if (!tmpaop_dead)
8943 _push (PAIR_HL);
8944 pushed_hl = true;
8947 if (aopInReg (left, offset, A_IDX) ||
8948 (aopInReg (tmpaop, 0, L_IDX) || aopInReg (tmpaop, 0, H_IDX)) && requiresHL (left))
8950 cheapMove (ASMOP_A, 0, left, offset, true);
8951 cheapMove (tmpaop, 0, right, offset, false);
8953 else
8955 cheapMove (tmpaop, 0, right, offset, true);
8956 cheapMove (ASMOP_A, 0, left, offset, true);
8958 emit3_o (offset ? A_SBC : A_SUB, ASMOP_A, 0, tmpaop, 0);
8960 else if (right->type != AOP_LIT)
8962 if ((requiresHL (left) && left->type != AOP_REG || requiresHL (right) && right->type != AOP_REG) && !hl_dead)
8964 _push (PAIR_HL);
8965 pushed_hl = true;
8968 if ((aopInReg (right, offset, IYL_IDX) || aopInReg (right, offset, IYH_IDX)) && !HAS_IYL_INST) // From here on all codepaths needs to use right as operand.
8969 UNIMPLEMENTED;
8970 else if (right->type == AOP_STL && offset < 2)
8972 cheapMove (ASMOP_A, 0, left, offset, true);
8973 if (!hl_dead && !pushed_hl)
8975 _push (PAIR_HL);
8976 pushed_hl = true;
8978 genMove (ASMOP_HL, right, false, true, false, false);
8979 emit3 (offset ? A_SBC : A_SUB, ASMOP_A, offset ? ASMOP_H : ASMOP_L);
8981 else if (!offset)
8983 if (aopIsLitVal (left, offset, 1, 0x00) && aopInReg (right, offset, A_IDX))
8984 emit3 (A_NEG, 0, 0);
8985 else
8987 if (aopIsLitVal (left, offset, 1, 0x00) && !aopInReg (left, offset, A_IDX))
8988 emit3 (A_XOR, ASMOP_A, ASMOP_A);
8989 else
8990 cheapMove (ASMOP_A, 0, left, offset, true);
8991 if ((aopInReg (right, offset, L_IDX) || aopInReg (right, offset, H_IDX)) && pushed_hl)
8993 _pop (PAIR_HL);
8994 pushed_hl = false;
8996 emit3_o (A_SUB, ASMOP_A, 0, right, offset);
8999 else if (aopIsLitVal (left, offset, 1, 0x00) && !aopInReg (left, offset, A_IDX) && size == 1) // For the last byte, we can do an optimization that results in the same value in a, but different carry.
9001 emit3 (A_SBC, ASMOP_A, ASMOP_A);
9002 emit3_o (A_SUB, ASMOP_A, 0, right, offset);
9004 else
9006 cheapMove (ASMOP_A, 0, left, offset, true);
9007 if ((aopInReg (right, offset, L_IDX) || aopInReg (right, offset, H_IDX)) && pushed_hl)
9009 _pop (PAIR_HL);
9010 pushed_hl = false;
9012 emit3_o (A_SBC, ASMOP_A, 0, right, offset);
9015 else // right is a literal.
9017 if (requiresHL (left) && left->type != AOP_REG && !hl_dead)
9019 _push (PAIR_HL);
9020 pushed_hl = true;
9023 cheapMove (ASMOP_A, 0, left, offset, true);
9025 /* first add without previous c */
9026 if (!offset)
9028 if (size == 0 && (unsigned int) (lit & 0x0FFL) == 0xFF)
9029 emit3 (A_DEC, ASMOP_A, 0);
9030 else
9032 if (!regalloc_dry_run)
9033 emit2 ("add a, !immedbyte", (unsigned int)(lit & 0x0fful));
9034 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9037 else
9038 emit2 ("adc a, !immedbyte", (unsigned int)((lit >> (offset * 8)) & 0x0fful));
9041 if (maskedbyte)
9043 emit2 ("and a, #0x%02x", topbytemask);
9044 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9047 if (pushed_hl)
9048 _pop (PAIR_HL);
9049 size--;
9050 _G.preserveCarry = !!size;
9051 cheapMove (result, offset++, ASMOP_A, 0, true);
9053 if ((left->type == AOP_PAIRPTR && left->aopu.aop_pairId == PAIR_HL || right->type == AOP_PAIRPTR && right->aopu.aop_pairId == PAIR_HL) &&
9054 size &&
9055 (aopInReg (result, offset, L_IDX) || aopInReg (result, offset, H_IDX)))
9056 UNIMPLEMENTED;
9061 /*-----------------------------------------------------------------*/
9062 /* genMinus - generates code for subtraction */
9063 /*-----------------------------------------------------------------*/
9064 static void
9065 genMinus (const iCode *ic, const iCode *ifx)
9067 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
9068 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
9069 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
9071 if (ifx && ifx->generated)
9073 wassert (ic->result->aop->size == 1 && IS_OP_LITERAL (ic->right) && ullFromVal (OP_VALUE (ic->right)) == 1);
9075 if (ic->result->aop->type == AOP_REG && (!aopInReg (ic->result->aop, 0, IYL_IDX) && !aopInReg (ic->result->aop, 0, IYH_IDX) || HAS_IYL_INST))
9077 cheapMove (ic->result->aop, 0, ic->left->aop, 0, isRegDead (A_IDX, ic));
9078 emit3 (A_DEC, ic->result->aop, 0);
9079 if (!IS_SM83 && aopInReg (ic->result->aop, 0, B_IDX) && IC_TRUE (ifx)) // This jump can likely be optimized to djnz.
9081 // cost2 can't handle negative costs, so we do this manually.
9082 regalloc_dry_run_cost_bytes--;
9083 if (IS_Z80 || IS_Z80N || IS_Z180)
9084 regalloc_dry_run_cost_states += -3.0 * regalloc_dry_run_state_scale;
9085 else if (IS_RAB)
9086 regalloc_dry_run_cost_states += -2.0 * regalloc_dry_run_state_scale;
9087 else if (IS_TLCS90)
9088 regalloc_dry_run_cost_states += +2.0 * regalloc_dry_run_state_scale; // For the TLCS-90, djnz is slower (typically still worth it for code size, though).
9089 else if (IS_EZ80_Z80 || IS_R800)
9090 regalloc_dry_run_cost_states += -1.0 * regalloc_dry_run_state_scale;
9093 else
9095 if (!isRegDead (A_IDX, ic))
9096 UNIMPLEMENTED;
9097 cheapMove (ASMOP_A, 0, ic->left->aop, 0, true);
9098 emit3 (A_DEC, ASMOP_A, 0);
9099 cheapMove (ic->result->aop, 0, ASMOP_A, 0, true);
9101 if (IC_TRUE (ifx))
9102 emit2 ("jp NZ, !tlabel", labelKey2num (IC_TRUE (ifx)->key));
9103 else
9104 emit2 ("jp Z, !tlabel", labelKey2num (IC_FALSE (ifx)->key));
9105 cost2 (2, 9.5f, 7.0f, 5.0f, 10.0f, 6.0f, 2.5f, 2.5f); // Assume both branches equally likely. Assume jp will be optimized to jr.
9107 else
9108 genSub (ic, ic->result->aop, ic->left->aop, ic->right->aop);
9110 _G.preserveCarry = FALSE;
9111 freeAsmop (IC_LEFT (ic), NULL);
9112 freeAsmop (IC_RIGHT (ic), NULL);
9113 freeAsmop (IC_RESULT (ic), NULL);
9116 /*-----------------------------------------------------------------*/
9117 /* genUminusFloat - unary minus for floating points */
9118 /*-----------------------------------------------------------------*/
9119 static void
9120 genUminusFloat (const iCode *ic, operand *result, operand *op)
9122 emitDebug ("; genUminusFloat");
9124 /* for this we just need to flip the
9125 first bit then copy the rest in place */
9127 if (!isRegDead (A_IDX, ic))
9128 _push (PAIR_AF);
9130 cheapMove (ASMOP_A, 0, op->aop, MSB32, true);
9132 emit2 ("xor a,!immedbyte", 0x80u);
9133 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9134 cheapMove (result->aop, MSB32, ASMOP_A, 0, true);
9136 genMove_o (result->aop, 0, op->aop, 0, op->aop->size - 1, !aopInReg (result->aop, MSB32, A_IDX), false, false, true, true);
9138 if (!isRegDead (A_IDX, ic))
9139 _pop (PAIR_AF);
9142 /*-----------------------------------------------------------------*/
9143 /* genUminus - unary minus code generation */
9144 /*-----------------------------------------------------------------*/
9145 static void
9146 genUminus (const iCode *ic)
9148 /* assign asmops */
9149 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
9150 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
9152 /* if both in bit space then special
9153 case */
9154 if (IC_RESULT (ic)->aop->type == AOP_CRY && IC_LEFT (ic)->aop->type == AOP_CRY)
9156 wassertl (0, "Left and right are in bit space");
9157 goto release;
9160 if (IS_FLOAT (operandType (IC_LEFT (ic))))
9161 genUminusFloat (ic, IC_RESULT (ic), IC_LEFT (ic));
9162 else
9163 genSub (ic, IC_RESULT (ic)->aop, ASMOP_ZERO, IC_LEFT (ic)->aop);
9165 release:
9166 _G.preserveCarry = FALSE;
9167 freeAsmop (IC_LEFT (ic), NULL);
9168 freeAsmop (IC_RESULT (ic), NULL);
9171 /*-----------------------------------------------------------------*/
9172 /* genMultOneChar - generates code for unsigned 8x8 multiplication */
9173 /*-----------------------------------------------------------------*/
9174 static void
9175 genMultOneChar (const iCode * ic)
9177 symbol *tlbl1, *tlbl2;
9178 bool savedB = false;
9180 asmop *result = ic->result->aop;
9181 int resultsize = result->size;
9183 if (ic->left->aop->size > 1 || ic->right->aop->size > 2)
9184 wassertl (0, "Large multiplication is handled through support function calls.");
9186 if (IS_SM83)
9188 wassertl (0, "Multiplication is handled through support function calls on sm83");
9189 return;
9192 if ((IS_Z180 || IS_EZ80_Z80 || IS_Z80N) && IC_RESULT (ic)->aop->type == AOP_REG)
9194 if (!IS_Z80N && (resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == B_IDX : isRegDead (B_IDX, ic))
9195 && result->aopu.aop_reg[0]->rIdx == C_IDX)
9197 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX ||
9198 IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == B_IDX)
9200 cheapMove (ASMOP_C, 0, IC_LEFT (ic)->aop, LSB, true);
9201 cheapMove (ASMOP_B, 0, IC_RIGHT (ic)->aop, LSB, true);
9203 else
9205 cheapMove (ASMOP_B, 0, IC_LEFT (ic)->aop, LSB, true);
9206 cheapMove (ASMOP_C, 0, IC_RIGHT (ic)->aop, LSB, true);
9208 emit2 ("mlt bc");
9209 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
9210 return;
9212 if ((resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == D_IDX : isRegDead (D_IDX, ic))
9213 && result->aopu.aop_reg[0]->rIdx == E_IDX)
9215 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX ||
9216 IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == D_IDX)
9218 cheapMove (ASMOP_E, 0, IC_LEFT (ic)->aop, LSB, true);
9219 cheapMove (ASMOP_D, 0, IC_RIGHT (ic)->aop, LSB, true);
9221 else
9223 cheapMove (ASMOP_D, 0, IC_LEFT (ic)->aop, LSB, true);
9224 cheapMove (ASMOP_E, 0, IC_RIGHT (ic)->aop, LSB, true);
9226 emit2 ("mlt de");
9227 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
9228 return;
9230 if (!IS_Z80N && IC_LEFT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->type == AOP_REG &&
9231 ((IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == H_IDX && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX ||
9232 IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == H_IDX) &&
9233 (resultsize > 1 ? result->aopu.aop_reg[1]->rIdx == H_IDX : isRegDead (H_IDX, ic))
9234 && result->aopu.aop_reg[0]->rIdx == L_IDX))
9236 emit2 ("mlt hl");
9237 spillPair (PAIR_HL);
9238 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
9239 return;
9243 if (IS_RAB && !IS_R2K && isPairDead (PAIR_HL, ic) && isPairDead (PAIR_BC, ic)) // A wait state bug makes mul unuseable in most scenarios on the original Rabbit 2000.
9245 const bool save_de = (resultsize > 1 && !isRegDead (D_IDX, ic) ||
9246 !isRegDead (E_IDX, ic) && !(IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX) && !(IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX));
9247 if (save_de)
9248 _push (PAIR_DE);
9250 if (aopInReg (ic->right->aop, 0, E_IDX))
9251 cheapMove (ASMOP_C, 0, ic->left->aop, 0, true);
9252 else if (aopInReg (ic->left->aop, 0, E_IDX))
9253 cheapMove (ASMOP_C, 0, ic->right->aop, 0, true);
9254 else if (aopInReg (ic->right->aop, 0, C_IDX))
9255 cheapMove (ASMOP_E, 0, ic->left->aop, 0, true);
9256 else if (aopInReg (ic->left->aop, 0, C_IDX))
9257 cheapMove (ASMOP_E, 0, ic->right->aop, 0, true);
9258 else
9260 cheapMove (ASMOP_C, 0, IC_LEFT (ic)->aop, 0, true);
9261 cheapMove (ASMOP_E, 0, IC_RIGHT (ic)->aop, 0, true);
9264 if (resultsize > 1)
9266 cheapMove (ASMOP_D, 0, ASMOP_ZERO, 0, true);
9267 cheapMove (ASMOP_B, 0, ASMOP_D, 0, true);
9270 emit2 ("mul");
9271 cost (1, 12);
9272 spillPair (PAIR_HL);
9274 genMove (result, resultsize > 1 ? ASMOP_BC : ASMOP_C, !isRegDead (A_IDX, ic), true, false, true);
9276 if (save_de)
9277 _pop (PAIR_DE);
9278 return;
9281 if (IS_R800 && isRegDead (HL_IDX, ic) && isRegDead (A_IDX, ic))
9283 if (aopInReg (ic->right->aop, 0, C_IDX) || aopInReg (ic->right->aop, 0, B_IDX) || aopInReg (ic->right->aop, 0, E_IDX) || aopInReg (ic->right->aop, 0, D_IDX))
9285 cheapMove (ASMOP_A, 0, ic->left->aop, 0, true);
9286 if (!regalloc_dry_run)
9287 emit2 ("multu a, %s", aopGet (ic->right->aop, 0, false));
9288 cost (2, 14);
9289 goto store_hl;
9291 else if (aopInReg (ic->left->aop, 0, C_IDX) || aopInReg (ic->left->aop, 0, B_IDX) || aopInReg (ic->left->aop, 0, E_IDX) || aopInReg (ic->left->aop, 0, D_IDX))
9293 cheapMove (ASMOP_A, 0, ic->right->aop, 0, true);
9294 if (!regalloc_dry_run)
9295 emit2 ("multu a, %s", aopGet (ic->left->aop, 0, false));
9296 cost (2, 14);
9297 goto store_hl;
9299 else if (isRegDead (B_IDX, ic))
9301 if (aopInReg (ic->right->aop, 0, A_IDX))
9302 cheapMove (ASMOP_B, 0, ic->left->aop, 0, false);
9303 else
9305 cheapMove (ASMOP_A, 0, ic->left->aop, 0, true);
9306 cheapMove (ASMOP_B, 0, ic->right->aop, 0, false);
9308 emit2 ("multu a, b");
9309 cost (2, 14);
9310 goto store_hl;
9312 else
9313 UNIMPLEMENTED;
9314 return;
9317 if (!isPairDead (PAIR_DE, ic))
9319 _push (PAIR_DE);
9320 _G.stack.pushedDE = TRUE;
9322 if (IS_RAB && !isPairDead (PAIR_BC, ic) ||
9323 !(IS_Z180 || IS_EZ80_Z80) && !isRegDead (B_IDX, ic))
9325 _push (PAIR_BC);
9326 savedB = TRUE;
9329 // genMult() already swapped operands if necessary.
9330 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX ||
9331 IC_RIGHT (ic)->aop->type == AOP_REG && IC_RIGHT (ic)->aop->aopu.aop_reg[0]->rIdx == H_IDX
9332 && !requiresHL (IC_LEFT (ic)->aop))
9334 cheapMove (ASMOP_E, 0, IC_LEFT (ic)->aop, 0, true);
9335 cheapMove (ASMOP_H, 0, IC_RIGHT (ic)->aop, 0, true);
9337 else
9339 cheapMove (ASMOP_E, 0, IC_RIGHT (ic)->aop, 0, true);
9340 cheapMove (ASMOP_H, 0, IC_LEFT (ic)->aop, 0, true);
9343 if (IS_Z180 || IS_EZ80_Z80)
9345 emit3 (A_LD, ASMOP_L, ASMOP_E);
9346 emit2 ("mlt hl");
9347 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
9349 else if (IS_RAB && !IS_R2K) // A wait state bug makes mul unuseable in most scenarios on the original Rabbit 2000.
9351 emit3 (A_LD, ASMOP_C, ASMOP_H);
9352 emit2 ("ld d, !immedbyte", 0x00u);
9353 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9354 emit3 (A_LD, ASMOP_B, ASMOP_D);
9355 emit2 ("mul");
9356 cost (1, 12);
9357 emit3 (A_LD, ASMOP_L, ASMOP_C);
9358 emit3 (A_LD, ASMOP_H, ASMOP_B);
9360 else
9362 tlbl1 = regalloc_dry_run ? 0 : newiTempLabel (0);
9363 tlbl2 = regalloc_dry_run ? 0 : newiTempLabel (0);
9364 emit2 ("ld l, !immedbyte", 0x00u);
9365 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9366 emit3 (A_LD, ASMOP_D, ASMOP_L);
9367 emit2 ("ld b, !immedbyte", 0x08u);
9368 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9369 regalloc_dry_run_state_scale = 8.0f;
9370 if (!regalloc_dry_run)
9371 emitLabel (tlbl1);
9372 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
9373 if (!regalloc_dry_run)
9374 emit2 ("jp NC, !tlabel", labelKey2num (tlbl2->key));
9375 cost2 (2 + IS_SM83, 9.5f, 7.0f, 5.0f, 10.0f, 11.0f, 2.5f, 2.5f);
9376 regalloc_dry_run_state_scale = 4.0f;
9377 emit3w (A_ADD, ASMOP_HL, ASMOP_DE);
9378 emitLabel (tlbl2);
9379 if (!regalloc_dry_run)
9380 emit2 ("djnz !tlabel", labelKey2num (tlbl1->key));
9381 cost2 (2, 12.375f, 8.75f, 5.0f, 0, 10.0f, 3.75f, 2.0f);
9382 regalloc_dry_run_state_scale = 1.0f;
9385 store_hl:
9386 spillPair (PAIR_HL);
9388 if (savedB)
9390 _pop (PAIR_BC);
9392 if (_G.stack.pushedDE)
9394 _pop (PAIR_DE);
9395 _G.stack.pushedDE = FALSE;
9398 genMove (result, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
9401 /*----------------------------------------------------------------------*/
9402 /* genMultTwoChar - generates code for 16x16->(16 to 32) multiplication */
9403 /*----------------------------------------------------------------------*/
9404 static void
9405 genMultTwoChar (const iCode *ic)
9407 operand *left = IC_LEFT (ic);
9408 operand *right = IC_RIGHT (ic);
9409 wassert (IS_RAB && !IS_R2K); // mul instruction is broken on Rabbit 2000.
9411 bool save_bc = !isPairDead(PAIR_BC, ic);
9412 bool save_de = !isPairDead(PAIR_DE, ic) && getPairId (left->aop) != PAIR_DE && getPairId (right->aop) != PAIR_DE;
9414 if (save_bc)
9415 _push (PAIR_BC);
9416 if (save_de)
9417 _push (PAIR_DE);
9419 if (getPairId (left->aop) == PAIR_BC || getPairId (right->aop) == PAIR_DE)
9421 if (right->aop->regs[C_IDX] >= 0 || right->aop->regs[B_IDX] >= 0)
9422 UNIMPLEMENTED;
9423 genMove (ASMOP_BC, left->aop, isRegDead (A_IDX, ic), right->aop->regs[L_IDX] < 0 && right->aop->regs[H_IDX] < 0, right->aop->regs[E_IDX] < 0 && right->aop->regs[D_IDX] < 0, true);
9424 genMove (ASMOP_DE, right->aop, isRegDead (A_IDX, ic), true, true, true);
9426 else
9428 if (left->aop->regs[C_IDX] >= 0 || left->aop->regs[B_IDX] >= 0)
9429 UNIMPLEMENTED;
9430 genMove (ASMOP_BC, right->aop, isRegDead (A_IDX, ic), left->aop->regs[L_IDX] < 0 && left->aop->regs[H_IDX] < 0, left->aop->regs[E_IDX] < 0 && left->aop->regs[D_IDX] < 0, true);
9431 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), true, true, true);
9434 emit2 ("mul");
9435 cost (1, 12);
9437 if (save_de)
9438 _pop (PAIR_DE);
9440 genMove (ic->result->aop, ASMOP_HLBC, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), true, true);
9442 if (save_bc)
9444 if (ic->result->aop->regs[B_IDX] >= 0)
9445 poppairwithsavedreg (PAIR_BC, B_IDX, -1);
9446 else if (ic->result->aop->regs[C_IDX] >= 0)
9447 poppairwithsavedreg (PAIR_BC, C_IDX, -1);
9448 else
9449 _pop (PAIR_BC);
9453 /*-----------------------------------------------------------------*/
9454 /* genMult - generates code for multiplication */
9455 /*-----------------------------------------------------------------*/
9456 static void
9457 genMult (iCode *ic)
9459 int val;
9460 /* If true then the final operation should be a subtract */
9461 bool active = false;
9462 bool byteResult;
9463 bool add_in_hl = false;
9464 int a_cost = 0, l_cost = 0;
9465 PAIR_ID pair;
9467 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
9468 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
9469 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
9471 byteResult = (IC_RESULT (ic)->aop->size == 1);
9473 if (IC_LEFT (ic)->aop->size > 2 || IC_RIGHT (ic)->aop->size > 2)
9474 wassertl (0, "Large multiplication is handled through support function calls.");
9476 /* Swap left and right such that right is a literal */
9477 if (IC_LEFT (ic)->aop->type == AOP_LIT)
9479 operand *t = IC_RIGHT (ic);
9480 IC_RIGHT (ic) = IC_LEFT (ic);
9481 IC_LEFT (ic) = t;
9484 if (IS_RAB && !IS_R2K && IC_RIGHT (ic)->aop->type != AOP_LIT && !byteResult && IC_LEFT (ic)->aop->size == 2 && IC_RIGHT (ic)->aop->size == 2)
9486 genMultTwoChar (ic);
9487 goto release;
9489 else if (IC_RIGHT (ic)->aop->type != AOP_LIT)
9491 genMultOneChar (ic);
9492 goto release;
9495 wassertl (IC_RIGHT (ic)->aop->type == AOP_LIT, "Right must be a literal.");
9497 val = (int) ulFromVal (IC_RIGHT (ic)->aop->aopu.aop_lit);
9498 wassertl (val != 1, "Can't multiply by 1");
9500 // Try to use mlt.
9501 if ((IS_Z180 || IS_EZ80_Z80 || IS_Z80N) && IC_LEFT (ic)->aop->size == 1 && IC_RIGHT (ic)->aop->size == 1 &&
9502 (byteResult || SPEC_USIGN (getSpec (operandType (IC_LEFT (ic)))) && SPEC_USIGN (getSpec (operandType (IC_RIGHT (ic))))))
9504 pair = getPairId (IC_RESULT (ic)->aop);
9505 if (pair == PAIR_INVALID && IC_RESULT (ic)->aop->type == AOP_REG)
9507 if (isRegDead (H_IDX, ic) && IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX)
9508 pair = PAIR_HL;
9509 else if (isRegDead (D_IDX, ic) && IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX)
9510 pair = PAIR_HL;
9511 else if (isRegDead (B_IDX, ic) && IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX)
9512 pair = PAIR_HL;
9514 else if (pair == PAIR_INVALID)
9515 pair = getDeadPairId (ic);
9517 if (pair == PAIR_INVALID)
9519 if (!(IC_RESULT (ic)->aop->type == AOP_REG &&
9520 (IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == L_IDX || IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == H_IDX ||
9521 !byteResult && (IC_RESULT (ic)->aop->aopu.aop_reg[1]->rIdx == L_IDX || IC_RESULT (ic)->aop->aopu.aop_reg[1]->rIdx == H_IDX))))
9522 pair = PAIR_HL;
9523 else if (!(IC_RESULT (ic)->aop->type == AOP_REG &&
9524 (IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX || IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == D_IDX ||
9525 !byteResult && (IC_RESULT (ic)->aop->aopu.aop_reg[1]->rIdx == E_IDX || IC_RESULT (ic)->aop->aopu.aop_reg[1]->rIdx == D_IDX))))
9526 pair = PAIR_DE;
9527 else
9528 pair = PAIR_BC;
9531 // For small operands under low register pressure, the standard approach is better than the mlt one.
9532 if (byteResult && val <= 6 && isPairDead (PAIR_HL, ic) && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) &&
9533 !(IC_RESULT (ic)->aop->type == AOP_REG && (IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX || IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX)))
9534 goto no_mlt;
9536 if (IS_Z80N && pair != PAIR_DE)
9537 goto no_mlt;
9539 asmop *pairop = pair == PAIR_HL ? ASMOP_HL : (pair == PAIR_DE ? ASMOP_DE : ASMOP_BC);
9541 if (!isPairDead (pair, ic))
9542 _push (pair);
9544 switch (pair)
9546 case PAIR_HL:
9547 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == H_IDX)
9548 cheapMove (ASMOP_L, 0, IC_RIGHT (ic)->aop, 0, true);
9549 else
9551 cheapMove (ASMOP_L, 0, IC_LEFT (ic)->aop, 0, true);
9552 cheapMove (ASMOP_H, 0, IC_RIGHT (ic)->aop, 0, true);
9554 break;
9555 case PAIR_DE:
9556 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == D_IDX)
9557 cheapMove (ASMOP_E, 0, IC_RIGHT (ic)->aop, 0, true);
9558 else
9560 cheapMove (ASMOP_E, 0, IC_LEFT (ic)->aop, 0, true);
9561 cheapMove (ASMOP_D, 0, IC_RIGHT (ic)->aop, 0, true);
9563 break;
9564 default:
9565 wassert (pair == PAIR_BC);
9566 if (IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == B_IDX)
9567 cheapMove (ASMOP_C, 0, IC_RIGHT (ic)->aop, 0, true);
9568 else
9570 cheapMove (ASMOP_C, 0, IC_LEFT (ic)->aop, 0, true);
9571 cheapMove (ASMOP_B, 0, IC_RIGHT (ic)->aop, 0, true);
9573 break;
9576 emit2 ("mlt %s", _pairs[pair].name);
9577 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
9579 genMove_o (IC_RESULT (ic)->aop, 0, pairop, 0, 2 - byteResult, true, pair == PAIR_HL || isPairDead (PAIR_HL, ic), pair == PAIR_DE || isPairDead (PAIR_DE, ic), true, true);
9581 if (!isPairDead (pair, ic))
9582 _pop (pair);
9584 goto release;
9586 no_mlt:
9588 if (IS_RAB && !IS_R2K && isPairDead(PAIR_DE, ic) && isPairDead(PAIR_BC, ic) && // mul might be cheaper than a series of additions. mul is broken on the original Rabbit 2000.
9589 !byteResult && (IC_LEFT (ic)->aop->size > 1 || SPEC_USIGN (getSpec (operandType (IC_LEFT (ic))))))
9591 int num_add = 0;
9592 bool active = false;
9593 unsigned int i = val;
9594 for (int count = 0; count < 16; count++)
9596 if (count != 0 && active)
9597 num_add++;
9598 if (i & 0x8000u)
9600 active = true;
9601 num_add += active;
9603 i <<= 1;
9606 if(num_add > (optimize.codeSize ? 4 : 6))
9608 if (getPairId (IC_LEFT (ic)->aop) == PAIR_BC)
9609 fetchPair (PAIR_DE, IC_RIGHT (ic)->aop);
9610 else
9612 fetchPairLong (PAIR_DE, IC_LEFT(ic)->aop, ic, 0);
9613 fetchPair (PAIR_BC, IC_RIGHT (ic)->aop);
9615 emit2 ("mul");
9616 cost (1, 12);
9617 spillPair (PAIR_HL);
9618 genMove (IC_RESULT (ic)->aop, ASMOP_BC, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
9619 goto release;
9623 pair = PAIR_DE;
9624 if (getPairId (IC_LEFT (ic)->aop) == PAIR_BC ||
9625 (byteResult || isRegDead (B_IDX, ic)) && IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == C_IDX)
9626 pair = PAIR_BC;
9627 if (isPairDead (PAIR_BC, ic) && !(IC_LEFT (ic)->aop->type == AOP_REG && IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx == E_IDX))
9628 pair = PAIR_BC;
9630 if (pair == PAIR_DE && (byteResult ? !isRegDead (E_IDX, ic) : !isPairDead (PAIR_DE, ic)))
9632 _push (PAIR_DE);
9633 _G.stack.pushedDE = TRUE;
9636 /* Use 16-bit additions even for 8-bit result when the operands are in the right places. */
9637 if (byteResult)
9639 if (!aopInReg (IC_LEFT (ic)->aop, 0, A_IDX))
9640 a_cost += ld_cost (ASMOP_A, 0, IC_LEFT (ic)->aop, 0, false);
9641 if (!aopInReg (IC_RESULT (ic)->aop, 0, A_IDX))
9642 a_cost += ld_cost (IC_RESULT (ic)->aop, 0, ASMOP_A, 0, false);
9643 if (IC_LEFT (ic)->aop->type != AOP_REG || IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx != L_IDX)
9644 l_cost += ld_cost (ASMOP_L, 0, IC_LEFT (ic)->aop, 0, false);
9645 if (IC_RESULT (ic)->aop->type != AOP_REG || IC_RESULT (ic)->aop->aopu.aop_reg[0]->rIdx != L_IDX)
9646 l_cost += ld_cost (IC_RESULT (ic)->aop, 0, ASMOP_L, 0, false);
9648 add_in_hl = (!byteResult || isPairDead (PAIR_HL, ic) && l_cost < a_cost);
9650 if (byteResult)
9652 cheapMove (add_in_hl ? ASMOP_L : ASMOP_A, 0, IC_LEFT (ic)->aop, 0, true);
9653 if (IC_LEFT (ic)->aop->type != AOP_REG || IC_LEFT (ic)->aop->aopu.aop_reg[0]->rIdx != (pair == PAIR_BC ? C_IDX : E_IDX))
9654 cheapMove (pair == PAIR_BC ? ASMOP_C : ASMOP_E, 0, add_in_hl ? ASMOP_L : ASMOP_A, 0, true);
9656 else if (IC_LEFT (ic)->aop->size == 1 && !SPEC_USIGN (getSpec (operandType (IC_LEFT (ic)))))
9658 cheapMove (pair == PAIR_BC ? ASMOP_C : ASMOP_E, 0, IC_LEFT (ic)->aop, 0, true);
9659 emit2 ("ld a, %s", _pairs[pair].l);
9660 ld_cost (ASMOP_A, 0, ASMOP_L, 0, true);
9661 emit3 (A_RLCA, 0, 0);
9662 emit3 (A_SBC, ASMOP_A, ASMOP_A);
9663 emit2 ("ld %s, a", _pairs[pair].h);
9664 ld_cost (ASMOP_L, 0, ASMOP_A, 0, true);
9665 emit2 ("ld l, %s", _pairs[pair].l);
9666 ld_cost (ASMOP_L, 0, pair == PAIR_HL ? ASMOP_L : pair == PAIR_DE ? ASMOP_E : ASMOP_C, 0, true);
9667 emit2 ("ld h, %s", _pairs[pair].h);
9668 ld_cost (ASMOP_L, 0, pair == PAIR_HL ? ASMOP_H : pair == PAIR_DE ? ASMOP_D : ASMOP_B, 0, true);
9670 else
9672 fetchPair (pair, IC_LEFT (ic)->aop);
9673 if (getPairId (IC_LEFT (ic)->aop) != PAIR_HL)
9675 emit2 ("ld l, %s", _pairs[pair].l);
9676 ld_cost (ASMOP_L, 0, pair == PAIR_HL ? ASMOP_L : pair == PAIR_DE ? ASMOP_E : ASMOP_C, 0, true);
9677 emit2 ("ld h, %s", _pairs[pair].h);
9678 ld_cost (ASMOP_H, 0, pair == PAIR_HL ? ASMOP_H : pair == PAIR_DE ? ASMOP_D : ASMOP_B, 0, true);
9682 if (!add_in_hl)
9684 unsigned long long add, sub;
9685 int topbit, nonzero;
9687 wassert(!csdOfVal (&topbit, &nonzero, &add, &sub, IC_RIGHT (ic)->aop->aopu.aop_lit, 0xff));
9689 // If the leading digits of the cse are 1 0 -1 we can use 0 1 1 instead to reduce the number of shifts.
9690 if (topbit >= 2 && (add & (1ull << topbit)) && (sub & (1ull << (topbit - 2))))
9692 add = (add & ~(1u << topbit)) | (3u << (topbit - 2));
9693 sub &= ~(1u << (topbit - 1));
9694 topbit--;
9697 for (int bit = topbit - 1; bit >= 0; bit--)
9699 emit3 (A_ADD, ASMOP_A, ASMOP_A);
9700 if ((add | sub) & (1ull << bit))
9702 emit2 (add & (1ull << bit) ? "add a, %s" : "sub a, %s", _pairs[pair].l);
9703 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
9707 else // Don't try to use CSD for hl, since subtraction there is more expensive than addition.
9709 unsigned int i = val;
9710 for (int count = 0; count < 16; count++)
9712 if (count != 0 && active)
9713 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
9714 if (i & 0x8000u)
9716 if (active)
9718 emit2 ("add hl, %s", _pairs[pair].name);
9719 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
9721 active = true;
9723 i <<= 1;
9725 spillPair (PAIR_HL);
9728 if (_G.stack.pushedDE)
9730 _pop (PAIR_DE);
9731 _G.stack.pushedDE = false;
9734 genMove (IC_RESULT (ic)->aop, add_in_hl ? ASMOP_HL : ASMOP_A, true, add_in_hl || isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
9736 release:
9737 freeAsmop (IC_LEFT (ic), NULL);
9738 freeAsmop (IC_RIGHT (ic), NULL);
9739 freeAsmop (IC_RESULT (ic), NULL);
9742 /*-----------------------------------------------------------------*/
9743 /* genDiv - generates code for division */
9744 /*-----------------------------------------------------------------*/
9745 static void
9746 genDiv (const iCode * ic)
9748 /* Shouldn't occur - all done through function calls */
9749 wassertl (0, "Division is handled through support function calls");
9752 /*-----------------------------------------------------------------*/
9753 /* genMod - generates code for division */
9754 /*-----------------------------------------------------------------*/
9755 static void
9756 genMod (const iCode * ic)
9758 /* Shouldn't occur - all done through function calls */
9759 wassert (0);
9762 /*-----------------------------------------------------------------*/
9763 /* genIfxJump :- will create a jump depending on the ifx */
9764 /*-----------------------------------------------------------------*/
9765 static void
9766 genIfxJump (iCode * ic, char *jval)
9768 symbol *jlbl;
9769 const char *inst;
9771 /* if true label then we jump if condition
9772 supplied is true */
9773 if (IC_TRUE (ic))
9775 jlbl = IC_TRUE (ic);
9776 if (!strcmp (jval, "a"))
9778 emit3 (A_OR, ASMOP_A, ASMOP_A);
9779 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
9780 inst = "NZ";
9782 else if (!strcmp (jval, "z"))
9784 inst = "Z";
9786 else if (!strcmp (jval, "nz"))
9788 inst = "NZ";
9790 else if (!strcmp (jval, "c"))
9792 inst = "C";
9794 else if (!strcmp (jval, "nc"))
9796 inst = "NC";
9798 else if (!strcmp (jval, "m"))
9800 inst = "M";
9802 else if (!strcmp (jval, "p"))
9804 inst = "P";
9806 else if (!strcmp (jval, "po"))
9808 inst = "PO";
9810 else if (!strcmp (jval, "pe"))
9812 inst = "PE";
9814 else
9816 /* The buffer contains the bit on A that we should test */
9817 emit2 ("bit %s, a", jval);
9818 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
9819 inst = "NZ";
9822 else
9824 /* false label is present */
9825 jlbl = IC_FALSE (ic);
9826 if (!strcmp (jval, "a"))
9828 emit3 (A_OR, ASMOP_A, ASMOP_A);
9829 inst = "Z";
9831 else if (!strcmp (jval, "z"))
9833 inst = "NZ";
9835 else if (!strcmp (jval, "nz"))
9837 inst = "Z";
9839 else if (!strcmp (jval, "c"))
9841 inst = "NC";
9843 else if (!strcmp (jval, "nc"))
9845 inst = "C";
9847 else if (!strcmp (jval, "m"))
9849 inst = "P";
9851 else if (!strcmp (jval, "p"))
9853 inst = "M";
9855 else if (!strcmp (jval, "po"))
9857 inst = "PE";
9859 else if (!strcmp (jval, "pe"))
9861 inst = "PO";
9863 else
9865 /* The buffer contains the bit on A that we should test */
9866 emit2 ("bit %s, a", jval);
9867 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
9868 inst = "Z";
9871 /* Z80 can do a conditional long jump */
9872 if (!regalloc_dry_run)
9873 emit2 ("jp %s, !tlabel", inst, labelKey2num (jlbl->key));
9874 cost2 (3, 10.0f, 7.5f,7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume either way equally likely.
9877 #if DISABLED
9878 static const char *
9879 _getPairIdName (PAIR_ID id)
9881 return _pairs[id].name;
9883 #endif
9885 /** Generic compare for > or <
9887 static void
9888 genCmp (operand * left, operand * right, operand * result, iCode * ifx, int sign, const iCode * ic)
9890 int size, offset = 0;
9891 unsigned long long lit = 0ull;
9892 bool result_in_carry = FALSE;
9893 int a_always_byte = -1;
9894 bool started = false;
9895 bool inv = false;
9897 /* if left & right are bit variables */
9898 if (left->aop->type == AOP_CRY && right->aop->type == AOP_CRY)
9900 /* Can't happen on the Z80 */
9901 wassertl (0, "Tried to compare two bits");
9903 else
9905 /* Do a long subtract of right from left. */
9906 size = max (left->aop->size, right->aop->size);
9908 if (right->aop->type == AOP_SFR) /* Avoid overwriting A */
9910 bool save_a, save_b, save_bc;
9911 wassertl (size == 1, "Right side sfr in comparison with more than 8 bits.");
9913 save_b = !isRegDead (B_IDX, ic);
9914 save_bc = (save_b && !isRegDead (C_IDX, ic));
9915 save_a = (aopInReg (left->aop, 0, A_IDX) ||
9916 aopInReg (left->aop, 0, B_IDX) && save_b ||
9917 aopInReg (left->aop, 0, C_IDX) && !save_b && save_bc);
9919 if (save_bc)
9920 _push (PAIR_BC);
9921 if (save_a)
9923 cheapMove (ASMOP_A, 0, right->aop, 0, true);
9924 _push (PAIR_AF);
9926 else
9927 cheapMove (ASMOP_A, 0, right->aop, 0, true);
9928 cheapMove (save_b ? ASMOP_C : ASMOP_B, 0, ASMOP_A, 0, true);
9929 if (save_a)
9930 _pop (PAIR_AF);
9931 else
9932 cheapMove (ASMOP_A, 0, left->aop, 0, true);
9933 emit3_o (A_SUB, ASMOP_A, 0, save_b ? ASMOP_C : ASMOP_B, offset);
9934 if (save_bc)
9935 _pop (PAIR_BC);
9936 result_in_carry = TRUE;
9937 goto fix;
9940 // Preserve A if necessary
9941 if (ifx && size == 1 && !sign && aopInReg (left->aop, 0, A_IDX) && !isRegDead (A_IDX, ic) &&
9942 (right->aop->type == AOP_LIT || right->aop->type == AOP_REG && right->aop->aopu.aop_reg[offset]->rIdx != IYL_IDX && right->aop->aopu.aop_reg[offset]->rIdx != IYH_IDX || right->aop->type == AOP_STK))
9944 emit3 (A_CP, ASMOP_A, right->aop);
9945 result_in_carry = true;
9946 goto release;
9948 else if (ifx && size == 1 && !sign && aopInReg (right->aop, 0, A_IDX) && left->aop->type == AOP_LIT && ullFromVal (left->aop->aopu.aop_lit) < 255)
9950 emit2 ("cp a, !immedbyte", (unsigned int)(ullFromVal (left->aop->aopu.aop_lit) + 1));
9951 cost2 (2, 7, 6, 4, 8, 6, 2, 2);
9952 result_in_carry = true;
9953 inv = true;
9954 goto release;
9957 if (right->aop->type == AOP_LIT && !ullFromVal (right->aop->aopu.aop_lit)) // special case: comparison to 0. Do it here early, so we don't run into sm83 workarounds below.
9959 if (!sign)
9961 /* No sign so it's always false */
9962 emit3 (A_CP, ASMOP_A, ASMOP_A);
9963 result_in_carry = TRUE;
9965 else
9967 if (!(result->aop->type == AOP_CRY && result->aop->size) && ifx &&
9968 (left->aop->type == AOP_REG || left->aop->type == AOP_STK && !IS_SM83))
9970 if (!regalloc_dry_run)
9971 emit2 ("bit 7, %s", aopGet (left->aop, left->aop->size - 1, FALSE));
9972 if (left->aop->type == AOP_REG)
9973 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
9974 else
9975 cost2 (4 - IS_TLCS90, 20, 15, 10, 6, 10, 5, 5);
9976 genIfxJump (ifx, "nz");
9977 return;
9979 /* Just load in the top most bit */
9980 cheapMove (ASMOP_A, 0, left->aop, left->aop->size - 1, true);
9981 if (!(result->aop->type == AOP_CRY && result->aop->size) && ifx)
9983 genIfxJump (ifx, "7");
9984 return;
9986 else
9988 if (ifx)
9990 genIfxJump (ifx, "nc");
9991 return;
9993 result_in_carry = FALSE;
9996 goto release;
9999 // On the SM83 we can't afford to adjust HL as it may trash the carry.
10000 if (size > 1 && (IS_SM83 || IY_RESERVED) &&
10001 left->aop->type != AOP_REG && requiresHL (left->aop) && left->aop->type != AOP_STL &&
10002 right->aop->type != AOP_REG && requiresHL (right->aop) && right->aop->type != AOP_STL)
10004 if (!isPairDead (PAIR_DE, ic))
10005 _push (PAIR_DE);
10007 pointPairToAop (PAIR_DE, left->aop, 0);
10008 pointPairToAop (PAIR_HL, right->aop, 0);
10010 while (size--)
10012 emit2 ("ld a, !mems", "de");
10013 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
10014 if (size != 0)
10015 emit3w (A_INC, ASMOP_DE, 0);
10016 emit2 ("%s a, !*hl", offset == 0 ? "sub" : "sbc");
10017 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10018 if (size != 0)
10019 emit3w (A_INC, ASMOP_HL, 0);
10020 offset++;
10022 if (sign && IS_SM83)
10024 wassert(isPairDead (PAIR_DE, ic));
10025 emit2 ("ld a, !mems", "de");
10026 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
10027 emit3 (A_LD, ASMOP_D, ASMOP_A);
10028 emit2 ("ld e, !*hl");
10029 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10032 spillPair (PAIR_DE);
10033 if (!isPairDead (PAIR_DE, ic))
10034 _pop (PAIR_DE);
10036 spillPair (PAIR_HL);
10037 result_in_carry = TRUE;
10038 goto fix;
10040 else if (size > 1 && IS_SM83 && (requiresHL (right->aop) && right->aop->type != AOP_REG && right->aop->type != AOP_STL && !requiresHL (left->aop)))
10042 if (!regalloc_dry_run)
10043 aopGet (right->aop, LSB, FALSE);
10045 while (size--)
10047 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10048 emit2 ("%s a, !*hl", offset == 0 ? "sub" : "sbc");
10049 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10051 if (size != 0)
10052 emit3w (A_INC, ASMOP_HL, 0);
10053 offset++;
10055 if (sign)
10057 cheapMove (ASMOP_A, 0, left->aop, offset - 1, true);
10058 emit3 (A_LD, ASMOP_D, ASMOP_A);
10059 emit2 ("ld e, !*hl");
10060 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10062 spillPair (PAIR_HL);
10063 result_in_carry = TRUE;
10064 goto fix;
10066 else if (size > 1 && IS_SM83 && (!requiresHL (right->aop) && requiresHL (left->aop) && left->aop->type != AOP_REG && left->aop->type != AOP_STL))
10068 if (!regalloc_dry_run)
10069 aopGet (left->aop, LSB, FALSE);
10071 while (size--)
10073 emit2 ("ld a, !*hl");
10074 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10075 emit3_o (offset == 0 ? A_SUB : A_SBC, ASMOP_A, 0, right->aop, offset);
10077 if (size != 0)
10079 emit3w (A_INC, ASMOP_HL, 0);
10080 updatePair (PAIR_HL, 1);
10082 offset++;
10084 if (sign)
10086 emit2 ("ld d, !*hl");
10087 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
10088 cheapMove (ASMOP_A, 0, right->aop, offset - 1, true);
10089 emit3 (A_LD, ASMOP_E, ASMOP_A);
10091 result_in_carry = TRUE;
10092 goto fix;
10095 if (IS_SM83 && sign && right->aop->type != AOP_LIT && !aopInReg (left->aop, offset, A_IDX))
10097 cheapMove (ASMOP_A, 0, right->aop, size - 1, true);
10098 cheapMove (ASMOP_E, 0, ASMOP_A, 0, true);
10099 cheapMove (ASMOP_A, 0, left->aop, size - 1, true);
10100 cheapMove (ASMOP_D, 0, ASMOP_A, 0, true);
10103 if (right->aop->type == AOP_LIT)
10105 lit = ullFromVal (right->aop->aopu.aop_lit);
10107 while (!((lit >> (offset * 8)) & 0xffull))
10109 size--;
10110 offset++;
10113 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. */
10115 if (size == 2 && !(IS_SM83 || !ifx && requiresHL(result->aop) && result->aop->type != AOP_REG) && isPairDead (PAIR_HL, ic) && (isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic)) && (getPairId (left->aop) == PAIR_HL || IS_RAB && (left->aop->type == AOP_STK || left->aop->type == AOP_EXSTK)))
10117 PAIR_ID litpair = (isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC);
10118 fetchPair (PAIR_HL, left->aop);
10119 emit2 ("ld %s, !immedbyte", _pairs[litpair].name, (unsigned) ((lit ^ 0x8000u) & 0xffffu));
10120 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
10121 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
10122 emit2 ("ccf");
10123 cost2 (1, 4, 3, 2, 4, 2, 2, 1);
10124 if (IS_RAB)
10126 emit2 ("rr hl");
10127 cost (1, 2);
10129 else
10131 emit3 (A_RR, ASMOP_H, 0);
10132 emit3 (A_RR, ASMOP_L, 0);
10134 emit2 ("sbc hl, %s", _pairs[litpair].name);
10135 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
10136 spillPair (PAIR_HL);
10137 result_in_carry = true;
10138 goto release;
10141 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10142 if (size == 1)
10144 emit2 ("xor a, !immedbyte", 0x80u);
10145 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
10147 emit2 ("sub a, !immedbyte", (unsigned)(((lit >> (offset * 8)) & 0xff) ^ (size == 1 ? 0x80 : 0x00)));
10148 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
10149 size--;
10150 offset++;
10152 while (size--)
10154 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10155 if (!size)
10157 emit3 (A_RLA, 0, 0);
10158 emit2 ("ccf");
10159 cost2 (1, 4, 3, 2, 4, 2, 2, 1);
10160 emit3 (A_RRA, 0, 0);
10162 /* Subtract through, propagating the carry */
10163 emit2 ("sbc a, !immedbyte", (unsigned)(((lit >> (offset++ * 8)) & 0xff) ^ (size ? 0x00 : 0x80)));
10164 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
10166 result_in_carry = true;
10167 goto release;
10170 if (!IS_SM83 && (!sign || size > 2) && (getPartPairId (left->aop, offset) == PAIR_HL || size == 2 && left->aop->type == AOP_IY) && isPairDead (PAIR_HL, ic) &&
10171 (getPartPairId (right->aop, offset) == PAIR_DE || getPartPairId (right->aop, offset) == PAIR_BC))
10173 if (left->aop->type == AOP_DIR || left->aop->type == AOP_IY)
10174 fetchPair (PAIR_HL, left->aop);
10175 emit3 (A_XOR, ASMOP_A, ASMOP_A); // Clear carry.
10176 emit2 ("sbc hl, %s", _pairs[getPartPairId (right->aop, offset)].name);
10177 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
10178 spillPair (PAIR_HL);
10179 started = true;
10180 size -= 2;
10181 offset += 2;
10183 else if (left->aop->type == AOP_LIT && !aopInReg (right->aop, offset, A_IDX) && isRegDead (A_IDX, ic))
10185 bool pushed_hl = false;
10186 if (byteOfVal (left->aop->aopu.aop_lit, offset) == 0x00)
10187 emit3 (A_XOR, ASMOP_A, ASMOP_A);
10188 else
10189 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10190 if (requiresHL (right->aop) && right->aop->type != AOP_REG && !isPairDead (PAIR_HL, ic))
10192 _push (PAIR_HL);
10193 pushed_hl = true;
10195 if (size > 1)
10197 emit3_o (A_CP, ASMOP_A, 0, right->aop, offset);
10198 started = true;
10199 a_always_byte = byteOfVal (left->aop->aopu.aop_lit, offset);
10201 else
10202 emit3_o (A_SUB, ASMOP_A, 0, right->aop, offset);
10203 if (pushed_hl)
10204 _pop (PAIR_HL);
10205 size--;
10206 offset++;
10209 /* Subtract through, propagating the carry */
10210 while (size)
10212 bool left_already_in_a = (left->aop->type == AOP_LIT && byteOfVal (left->aop->aopu.aop_lit, offset) == a_always_byte);
10214 if (started && !sign && aopIsLitVal (left->aop, offset, size, 0) && aopIsLitVal (right->aop, offset, size, 0)) // Skip leading zeroes.
10216 offset += size;
10217 size = 0;
10219 else if (!IS_SM83 && size >= 2 && (!sign || size > 2) && !left_already_in_a &&
10220 isPairDead (PAIR_HL, ic) &&
10221 (getPartPairId (left->aop, offset) == PAIR_HL || (left->aop->type == AOP_LIT || left->aop->type == AOP_IMMD || left->aop->type == AOP_HL || left->aop->type == AOP_IY || IS_RAB && left->aop->type == AOP_STK) && right->aop->regs[L_IDX] < offset && right->aop->regs[H_IDX] < offset) &&
10222 (getPartPairId (right->aop, offset) == PAIR_DE || getPartPairId (right->aop, offset) == PAIR_BC))
10224 genMove_o (ASMOP_HL, 0, left->aop, offset, 2, isRegDead (A_IDX, ic), true, false, true, !offset);
10225 if (!started)
10226 emit3 (A_CP, ASMOP_A, ASMOP_A);
10227 emit3w_o (A_SBC, ASMOP_HL, 0, right->aop, offset);
10228 spillPair (PAIR_HL);
10229 started = true;
10230 size -= 2;
10231 offset += 2;
10233 else if (!IS_SM83 && size >= 2 && (!sign || size > 2) && !left_already_in_a &&
10234 isPairDead (PAIR_HL, ic) && isPairDead (PAIR_DE, ic) && left->aop->regs[E_IDX] < offset + 1 && left->aop->regs[D_IDX] < offset + 1 &&
10235 (getPartPairId (left->aop, offset) == PAIR_HL || left->aop->type == AOP_LIT || left->aop->type == AOP_IMMD || left->aop->type == AOP_HL || left->aop->type == AOP_IY || IS_RAB && left->aop->type == AOP_STK) &&
10236 (right->aop->type == AOP_LIT || right->aop->type == AOP_IMMD || right->aop->type == AOP_HL || right->aop->type == AOP_IY || IS_RAB && right->aop->type == AOP_STK))
10238 genMove_o (ASMOP_DE, 0, right->aop, offset, 2, isRegDead (A_IDX, ic), getPartPairId (left->aop, offset) != PAIR_HL, true, true, !offset);
10239 genMove_o (ASMOP_HL, 0, left->aop, offset, 2, isRegDead (A_IDX, ic), true, false, true, !offset);
10240 if (!started)
10241 emit3 (A_CP, ASMOP_A, ASMOP_A);
10242 emit3w (A_SBC, ASMOP_HL, ASMOP_DE);
10243 spillPair (PAIR_HL);
10244 started = true;
10245 size -= 2;
10246 offset += 2;
10248 else if (right->aop->type == AOP_STL &&
10249 (isRegDead (B_IDX, ic) && left->aop->regs[B_IDX] <= offset || isRegDead (B_IDX, ic) && left->aop->regs[C_IDX] <= offset ))
10251 bool use_b = isRegDead (B_IDX, ic) && left->aop->regs[B_IDX] <= offset;
10252 if (!left_already_in_a)
10253 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10254 cheapMove (use_b ? ASMOP_B : ASMOP_C, 0, right->aop, offset, false);
10255 a_always_byte = -1;
10256 emit3_o (started ? A_SBC : A_SUB, ASMOP_A, 0, use_b ? ASMOP_B : ASMOP_C, 0);
10257 started = true;
10258 size--;
10259 offset++;
10261 else if (right->aop->type != AOP_STL && !aopInReg (right->aop, offset, A_IDX))
10263 if (!left_already_in_a)
10264 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10265 a_always_byte = -1;
10266 emit3_o (started ? A_SBC : A_SUB, ASMOP_A, 0, right->aop, offset);
10267 started = true;
10268 size--;
10269 offset++;
10271 else
10273 UNIMPLEMENTED;
10274 size--;
10275 offset++;
10279 fix:
10280 /* There is no good signed compare in the Z80, so we need workarounds */
10281 if (sign)
10283 if (!IS_SM83) /* Directly check for overflow, can't be done on SM83 */
10285 if (!regalloc_dry_run)
10287 symbol *tlbl = newiTempLabel (NULL);
10288 emit2 (IS_RAB ? "jp LZ, !tlabel" : "jp PO, !tlabel", labelKey2num (tlbl->key));
10289 cost2 (2 + IS_SM83, 12, 8, 5, 12, 12, 3, 3); // Assume no overflow.
10290 emit2 ("xor a, !immedbyte", 0x80u);
10291 cost (2, 0); // Assume no overflow.
10292 emitLabelSpill (tlbl);
10294 result_in_carry = FALSE;
10296 else /* Do it the hard way */
10298 /* Test if one operand is negative, while the other is not. If this is the
10299 case we can easily decide which one is greater, and we set/reset the carry
10300 flag. If not, then the unsigned compare gave the correct result and we
10301 don't change the carry flag. */
10302 symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel (0);
10303 symbol *tlbl2 = regalloc_dry_run ? 0 : newiTempLabel (0);
10304 emit2 ("bit 7, e");
10305 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
10306 if (!regalloc_dry_run)
10307 emit2 ("jp Z, !tlabel", labelKey2num (tlbl1->key));
10308 emit2 ("bit 7, d");
10309 if (!regalloc_dry_run)
10310 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl2->key));
10311 emit2 ("cp a, a");
10312 if (!regalloc_dry_run)
10313 emit2 ("jp !tlabel", labelKey2num (tlbl2->key));
10314 emitLabelSpill (tlbl1);
10315 emit2 ("bit 7, d");
10316 if (!regalloc_dry_run)
10317 emit2 ("jp Z, !tlabel", labelKey2num (tlbl2->key));
10318 emit2 ("scf");
10319 emitLabelSpill (tlbl2);
10320 regalloc_dry_run_cost += 18;
10321 result_in_carry = true;
10324 else
10325 result_in_carry = true;
10328 release:
10329 if (result->aop->type == AOP_CRY && result->aop->size)
10331 wassert (!inv);
10332 if (!result_in_carry)
10334 /* Shift the sign bit up into carry */
10335 emit3 (A_RLCA, 0, 0);
10337 outBitC (result);
10339 else
10341 /* if the result is used in the next
10342 ifx conditional branch then generate
10343 code a little differently */
10344 if (ifx)
10346 if (!result_in_carry)
10348 wassert (!inv);
10349 if (!IS_SM83)
10350 genIfxJump (ifx, "m");
10351 else
10353 emit3 (A_RLCA, 0, 0);
10354 genIfxJump (ifx, "c");
10357 else
10358 genIfxJump (ifx, inv ? "nc" : "c");
10360 else
10362 wassert (!inv);
10363 if (!result_in_carry)
10365 /* Shift the sign bit up into carry */
10366 emit3 (A_RLCA, 0, 0);
10368 outBitC (result);
10370 /* leave the result in acc */
10374 /*-----------------------------------------------------------------*/
10375 /* genCmpGt :- greater than comparison */
10376 /*-----------------------------------------------------------------*/
10377 static void
10378 genCmpGt (iCode * ic, iCode * ifx)
10380 operand *left, *right, *result;
10381 sym_link *letype, *retype;
10382 int sign;
10384 left = IC_LEFT (ic);
10385 right = IC_RIGHT (ic);
10386 result = IC_RESULT (ic);
10388 sign = 0;
10389 if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
10391 letype = getSpec (operandType (left));
10392 retype = getSpec (operandType (right));
10393 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
10396 /* assign the asmops */
10397 aopOp (left, ic, FALSE, FALSE);
10398 aopOp (right, ic, FALSE, FALSE);
10399 aopOp (result, ic, TRUE, FALSE);
10401 if (!IS_BITVAR (operandType (left)) && (!IS_BITINT (operandType (left)) || !(SPEC_BITINTWIDTH (operandType (left)) % 8)) &&
10402 !IS_BITVAR (operandType (right)) && (!IS_BITINT (operandType (right)) || !(SPEC_BITINTWIDTH (operandType (right)) % 8)) &&
10403 aopIsLitBit (left->aop, left->aop->size * 8 - 1, false) && aopIsLitBit (right->aop, right->aop->size * 8 - 1, false))
10404 sign = 0;
10406 if (max (left->aop->size, right->aop->size) > 1 && (couldDestroyCarry (left->aop) || couldDestroyCarry (right->aop)))
10408 if ((requiresHL (IC_RESULT (ic)->aop) && IC_RESULT (ic)->aop->type != AOP_REG || requiresHL (left->aop) && left->aop->type != AOP_REG || requiresHL (right->aop) && right->aop->type != AOP_REG) &&
10409 (left->aop->regs[L_IDX] > 0 || left->aop->regs[H_IDX] > 0 || right->aop->regs[L_IDX] > 0 || right->aop->regs[H_IDX] > 0) || !isPairDead (PAIR_HL, ic))
10410 UNIMPLEMENTED;
10411 else
10412 setupToPreserveCarry (result->aop, left->aop, right->aop);
10415 genCmp (right, left, result, ifx, sign, ic);
10417 _G.preserveCarry = FALSE;
10418 freeAsmop (left, NULL);
10419 freeAsmop (right, NULL);
10420 freeAsmop (result, NULL);
10423 /*-----------------------------------------------------------------*/
10424 /* genCmpLt - less than comparisons */
10425 /*-----------------------------------------------------------------*/
10426 static void
10427 genCmpLt (iCode * ic, iCode * ifx)
10429 operand *left, *right, *result;
10430 sym_link *letype, *retype;
10431 int sign;
10433 left = IC_LEFT (ic);
10434 right = IC_RIGHT (ic);
10435 result = IC_RESULT (ic);
10437 sign = 0;
10438 if (IS_SPEC (operandType (left)) && IS_SPEC (operandType (right)))
10440 letype = getSpec (operandType (left));
10441 retype = getSpec (operandType (right));
10442 sign = !(SPEC_USIGN (letype) | SPEC_USIGN (retype));
10445 /* assign the asmops */
10446 aopOp (left, ic, FALSE, FALSE);
10447 aopOp (right, ic, FALSE, FALSE);
10448 aopOp (result, ic, TRUE, FALSE);
10450 if (!IS_BITVAR (operandType (left)) && (!IS_BITINT (operandType (left)) || !(SPEC_BITINTWIDTH (operandType (left)) % 8)) &&
10451 !IS_BITVAR (operandType (right)) && (!IS_BITINT (operandType (right)) || !(SPEC_BITINTWIDTH (operandType (right)) % 8)) &&
10452 aopIsLitBit (left->aop, left->aop->size * 8 - 1, false) && aopIsLitBit (right->aop, right->aop->size * 8 - 1, false))
10453 sign = 0;
10455 if (max (left->aop->size, right->aop->size) > 1 && (couldDestroyCarry (left->aop) || couldDestroyCarry (right->aop)))
10457 if ((requiresHL (IC_RESULT (ic)->aop) && IC_RESULT (ic)->aop->type != AOP_REG || requiresHL (left->aop) && left->aop->type != AOP_REG || requiresHL (right->aop) && right->aop->type != AOP_REG) &&
10458 (left->aop->regs[L_IDX] > 0 || left->aop->regs[H_IDX] > 0 || right->aop->regs[L_IDX] > 0 || right->aop->regs[H_IDX] > 0) || !isPairDead (PAIR_HL, ic))
10459 UNIMPLEMENTED;
10460 else
10461 setupToPreserveCarry (result->aop, left->aop, right->aop);
10464 genCmp (left, right, result, ifx, sign, ic);
10466 _G.preserveCarry = FALSE;
10467 freeAsmop (left, NULL);
10468 freeAsmop (right, NULL);
10469 freeAsmop (result, NULL);
10472 /*-----------------------------------------------------------------*/
10473 /* gencjneshort - compare and jump if not equal */
10474 /* returns pair that still needs to be popped */
10475 /*-----------------------------------------------------------------*/
10476 static PAIR_ID
10477 gencjneshort (operand *left, operand *right, symbol *lbl, const iCode *ic)
10479 int size = max (left->aop->size, right->aop->size);
10480 int offset = 0;
10481 bool a_result = false;
10483 /* Swap the left and right if it makes the computation easier */
10484 if (left->aop->type == AOP_LIT || aopInReg (right->aop, 0, A_IDX))
10486 operand *t = right;
10487 right = left;
10488 left = t;
10491 /* Non-destructive compare */
10492 if (aopInReg (left->aop, 0, A_IDX) && !isRegDead (A_IDX, ic) &&
10493 (right->aop->type == AOP_LIT ||
10494 right->aop->type == AOP_REG && (HAS_IYL_INST || right->aop->aopu.aop_reg[offset]->rIdx != IYL_IDX && right->aop->aopu.aop_reg[offset]->rIdx != IYH_IDX) ||
10495 right->aop->type == AOP_STK))
10497 bool pushed_hl = false;
10498 if(requiresHL (right->aop) && right->aop->type != AOP_REG && !isPairDead(PAIR_HL, ic))
10500 _push (PAIR_HL);
10501 pushed_hl = true;
10504 if (right->aop->type == AOP_LIT && !byteOfVal (right->aop->aopu.aop_lit, 0))
10505 emit3 (A_OR, ASMOP_A, ASMOP_A);
10506 else
10507 emit3 (A_CP, ASMOP_A, right->aop);
10509 if (pushed_hl)
10510 _pop (PAIR_HL);
10512 if (!regalloc_dry_run)
10513 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10514 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, cp not optimzed into jr.
10516 /* if the right side is a literal then anything goes */
10517 else if (right->aop->type == AOP_LIT)
10519 while (size--)
10521 bool pushed_hl = false;
10522 bool next_zero = size && !byteOfVal (right->aop->aopu.aop_lit, offset + 1);
10524 if(requiresHL (left->aop) && left->aop->type != AOP_REG && !isPairDead(PAIR_HL, ic))
10526 _push (PAIR_HL);
10527 pushed_hl = true;
10530 // Test for 0 can be done more efficiently using or
10531 if (!byteOfVal (right->aop->aopu.aop_lit, offset))
10533 if (!a_result)
10535 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10536 emit3 (A_OR, ASMOP_A, ASMOP_A);
10538 else
10539 emit3_o (A_OR, ASMOP_A, 0, left->aop, offset);
10541 a_result = TRUE;
10543 else if ((aopInReg (left->aop, 0, A_IDX) && isRegDead (A_IDX, ic) ||
10544 left->aop->type == AOP_REG && left->aop->aopu.aop_reg[offset]->rIdx != IYL_IDX && left->aop->aopu.aop_reg[offset]->rIdx != IYH_IDX && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[offset]->rIdx)) &&
10545 byteOfVal (right->aop->aopu.aop_lit, offset) == 0x01 && !next_zero)
10547 emit3_o (A_DEC, left->aop, offset, 0, 0);
10548 a_result = aopInReg (left->aop, 0, A_IDX);
10550 else if (isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] < offset && size && byteOfVal (right->aop->aopu.aop_lit, offset) == 0xff &&
10551 (left->aop->type == AOP_REG || left->aop->type == AOP_STK) &&
10552 byteOfVal (right->aop->aopu.aop_lit, offset) == byteOfVal (right->aop->aopu.aop_lit, offset + 1))
10554 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10555 while (byteOfVal (right->aop->aopu.aop_lit, offset + 1) == 0xff && size)
10557 emit3_o (A_AND, ASMOP_A, 0, left->aop, ++offset);
10558 size--;
10560 emit3 (A_INC, ASMOP_A, 0);
10561 next_zero = size && !byteOfVal (right->aop->aopu.aop_lit, offset + 1);
10562 a_result = true;
10564 else if ((aopInReg (left->aop, 0, A_IDX) && isRegDead (A_IDX, ic) ||
10565 left->aop->type == AOP_REG && left->aop->aopu.aop_reg[offset]->rIdx != IYL_IDX && left->aop->aopu.aop_reg[offset]->rIdx != IYH_IDX && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[offset]->rIdx)) &&
10566 byteOfVal (right->aop->aopu.aop_lit, offset) == 0xff && !next_zero)
10568 emit3_o (A_INC, left->aop, offset, 0, 0);
10569 a_result = aopInReg (left->aop, 0, A_IDX);
10571 else
10573 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10575 if (byteOfVal (right->aop->aopu.aop_lit, offset) == 0x01)
10576 emit3 (A_DEC, ASMOP_A, 0);
10577 else if (byteOfVal (right->aop->aopu.aop_lit, offset) == 0xff)
10578 emit3 (A_INC, ASMOP_A, 0);
10579 else
10580 emit3_o (A_SUB, ASMOP_A, 0, right->aop, offset);
10582 a_result = true;
10585 if (pushed_hl)
10586 _pop (PAIR_HL);
10588 // Only emit jump now if there is no following test for 0 (which would just or to a current result in a)
10589 if (!(next_zero && a_result))
10591 if (!regalloc_dry_run)
10592 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10593 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, cp not optimzed into jr.
10595 offset++;
10598 /* if the right side is in a register or
10599 pointed to by HL, IX or IY */
10600 else if (right->aop->type == AOP_REG ||
10601 right->aop->type == AOP_HL ||
10602 right->aop->type == AOP_IY ||
10603 right->aop->type == AOP_STK ||
10604 right->aop->type == AOP_EXSTK ||
10605 right->aop->type == AOP_IMMD ||
10606 AOP_IS_PAIRPTR (right, PAIR_HL) || AOP_IS_PAIRPTR (right, PAIR_IX) || AOP_IS_PAIRPTR (right, PAIR_IY))
10608 while (size--)
10610 bool hl_dead = isRegDead (HL_IDX, ic) && left->aop->regs[L_IDX] < offset && left->aop->regs[H_IDX] < offset && right->aop->regs[L_IDX] < offset && right->aop->regs[H_IDX] < offset;
10611 bool iy_dead = isRegDead (IY_IDX, ic) && left->aop->regs[IYL_IDX] < offset && left->aop->regs[IYH_IDX] < offset && right->aop->regs[IYL_IDX] < offset && right->aop->regs[IYH_IDX] < offset;
10613 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))
10615 operand *t = right;
10616 right = left;
10617 left = t;
10620 if (!IS_SM83 && isPairDead (PAIR_HL, ic) &&
10621 (aopInReg (left->aop, offset, HL_IDX) && (aopInReg (right->aop, offset, BC_IDX) || aopInReg (right->aop, offset, DE_IDX) || getFreePairId (ic) != PAIR_INVALID) ||
10622 size == 1 && (aopInReg (right->aop, offset, BC_IDX) || aopInReg (right->aop, offset, DE_IDX))))
10624 PAIR_ID pair = getPairId_o (right->aop, offset);
10625 if (pair == PAIR_INVALID)
10626 pair = getFreePairId (ic);
10628 fetchPairLong (PAIR_HL, left->aop, ic, offset);
10629 fetchPairLong (pair, right->aop, 0, offset);
10630 emit3 (A_CP, ASMOP_A, ASMOP_A);
10631 emit2 ("sbc hl, %s", _pairs[pair].name);
10632 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
10633 if (!regalloc_dry_run)
10634 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10635 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, jp not optimzed into jr.
10636 spillPair (PAIR_HL);
10637 offset += 2;
10638 size--;
10639 continue;
10642 if (!hl_dead)
10643 genMove_o (ASMOP_A, 0, left->aop, offset, 1, true, false, false, iy_dead, true);
10644 else
10645 cheapMove (ASMOP_A, 0, left->aop, offset, true);
10646 if (right->aop->type == AOP_LIT && byteOfVal (right->aop->aopu.aop_lit, offset) == 0 || right->aop->type == AOP_STL && offset >= 2)
10648 emit3 (A_OR, ASMOP_A, ASMOP_A);
10649 if (!regalloc_dry_run)
10650 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10651 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, jp not optimzed into jr.
10653 else if (right->aop->type == AOP_STL && offset < 2)
10655 if (!hl_dead)
10656 _push (PAIR_HL);
10657 genMove_o (ASMOP_HL, 0, right->aop, 0, 2, false, true, false, false, true);
10658 emit3 (A_SUB, ASMOP_A, offset ? ASMOP_H : ASMOP_L);
10659 if (!hl_dead)
10660 _pop (PAIR_HL);
10661 if (!regalloc_dry_run)
10662 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10663 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, jp not optimzed into jr.
10665 else
10667 emit3_o (A_SUB, ASMOP_A, 0, right->aop, offset);
10668 if (!regalloc_dry_run)
10669 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10670 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, jp not optimzed into jr.
10672 offset++;
10675 /* right is in direct space or a pointer reg, need both a & b */
10676 else
10678 PAIR_ID pair;
10679 for (pair = PAIR_BC; pair <= PAIR_HL; pair++)
10681 if (((left->aop->type != AOP_PAIRPTR) || (left->aop->aopu.aop_pairId != pair)) &&
10682 ((right->aop->type != AOP_PAIRPTR) || (right->aop->aopu.aop_pairId != pair)))
10684 break;
10687 _push (pair);
10688 while (size--)
10690 cheapMove (pair == PAIR_BC ? ASMOP_BC : (pair == PAIR_DE ? ASMOP_DE : ASMOP_HL), 0, left->aop, offset, true);
10691 cheapMove (ASMOP_A, 0, right->aop, offset, true);
10692 emit2 ("sub a, %s", _pairs[pair].l);
10693 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
10694 if (!regalloc_dry_run)
10695 emit2 ("jp NZ, !tlabel", labelKey2num (lbl->key));
10696 cost2 (3, 10.0f, 7.5f, 7.0f, 14.0f, 11.0f, 3.5f, 3.0f); // Assume both branches equally likely, cp not optimzed into jr.
10697 offset++;
10699 return pair;
10701 return PAIR_INVALID;
10704 /*-----------------------------------------------------------------*/
10705 /* gencjne - compare and jump if not equal */
10706 /*-----------------------------------------------------------------*/
10707 static void
10708 gencjne (operand * left, operand * right, symbol * lbl, const iCode *ic)
10710 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
10711 PAIR_ID pop;
10713 pop = gencjneshort (left, right, lbl, ic);
10715 /* PENDING: ?? */
10716 if (!regalloc_dry_run)
10718 emit2 ("ld a,!one");
10719 emit2 ("jp !tlabel", labelKey2num (tlbl->key));
10720 emitLabelSpill (lbl);
10721 emit2 ("xor a,a");
10722 emitLabel (tlbl);
10724 regalloc_dry_run_cost += 6;
10725 _pop (pop);
10728 /*-----------------------------------------------------------------*/
10729 /* genCmpEq - generates code for equal to */
10730 /*-----------------------------------------------------------------*/
10731 static void
10732 genCmpEq (iCode * ic, iCode * ifx)
10734 operand *left, *right, *result;
10735 bool hl_touched;
10737 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
10738 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
10739 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
10741 hl_touched = (IC_LEFT (ic)->aop->type == AOP_HL || IC_RIGHT (ic)->aop->type == AOP_HL || IS_SM83
10742 && IC_LEFT (ic)->aop->type == AOP_STK || IS_SM83 && IC_RIGHT (ic)->aop->type == AOP_STK);
10744 /* Swap operands if it makes the operation easier. ie if:
10745 1. Left is a literal.
10747 if (IC_LEFT (ic)->aop->type == AOP_LIT || IC_RIGHT (ic)->aop->type != AOP_LIT && IC_RIGHT (ic)->aop->type != AOP_REG
10748 && IC_LEFT (ic)->aop->type == AOP_REG)
10750 operand *t = IC_RIGHT (ic);
10751 IC_RIGHT (ic) = IC_LEFT (ic);
10752 IC_LEFT (ic) = t;
10755 if (ifx && !result->aop->size)
10757 /* if they are both bit variables */
10758 if (left->aop->type == AOP_CRY && ((right->aop->type == AOP_CRY) || (right->aop->type == AOP_LIT)))
10760 wassertl (0, "Tried to compare two bits");
10762 else
10764 PAIR_ID pop;
10765 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
10766 pop = gencjneshort (left, right, tlbl, ic);
10767 if (IC_TRUE (ifx))
10769 if (pop != PAIR_INVALID)
10771 emit2 ("pop %s", _pairs[pop].name);
10772 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
10774 if (!regalloc_dry_run)
10775 emit2 ("jp !tlabel", labelKey2num (IC_TRUE (ifx)->key));
10776 regalloc_dry_run_cost += 3;
10777 if (!regalloc_dry_run)
10778 hl_touched ? emitLabelSpill (tlbl) : emitLabel (tlbl);
10779 else if (hl_touched)
10780 spillCached ();
10781 _pop (pop);
10783 else
10785 /* PENDING: do this better */
10786 symbol *lbl = regalloc_dry_run ? 0 : newiTempLabel (0);
10787 if (pop != PAIR_INVALID)
10789 emit2 ("pop %s", _pairs[pop].name);
10790 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
10792 if (!regalloc_dry_run)
10793 emit2 ("jp !tlabel", labelKey2num (lbl->key));
10794 regalloc_dry_run_cost += 3;
10795 if (!regalloc_dry_run)
10796 hl_touched ? emitLabelSpill (tlbl) : emitLabel (tlbl);
10797 else if (hl_touched)
10798 spillCached ();
10799 _pop (pop);
10800 if (!regalloc_dry_run)
10802 emit2 ("jp !tlabel", labelKey2num (IC_FALSE (ifx)->key));
10803 emitLabel (lbl);
10805 regalloc_dry_run_cost += 3;
10808 goto release;
10811 /* if they are both bit variables */
10812 if (left->aop->type == AOP_CRY && ((right->aop->type == AOP_CRY) || (right->aop->type == AOP_LIT)))
10814 wassertl (0, "Tried to compare a bit to either a literal or another bit");
10816 else
10818 gencjne (left, right, regalloc_dry_run ? 0 : newiTempLabel (NULL), ic);
10819 if (result->aop->type == AOP_CRY && result->aop->size)
10821 wassert (0);
10823 if (ifx)
10825 genIfxJump (ifx, "a");
10826 goto release;
10828 /* if the result is used in an arithmetic operation
10829 then put the result in place */
10830 if (result->aop->type != AOP_CRY)
10831 genMove (result->aop, ASMOP_A, true, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
10834 release:
10835 freeAsmop (left, NULL);
10836 freeAsmop (right, NULL);
10837 freeAsmop (result, NULL);
10840 /*-----------------------------------------------------------------*/
10841 /* genAndOp - for && operation */
10842 /*-----------------------------------------------------------------*/
10843 static void
10844 genAndOp (const iCode * ic)
10846 operand *left, *right, *result;
10848 /* note here that && operations that are in an if statement are
10849 taken away by backPatchLabels only those used in arthmetic
10850 operations remain */
10851 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
10852 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
10853 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
10855 /* if both are bit variables */
10856 if (left->aop->type == AOP_CRY && right->aop->type == AOP_CRY)
10858 wassertl (0, "Tried to and two bits");
10860 else
10862 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
10863 _toBoolean (left, TRUE);
10864 if (!regalloc_dry_run)
10865 emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
10866 regalloc_dry_run_cost += 3;
10867 _toBoolean (right, FALSE);
10868 if (!regalloc_dry_run)
10869 emitLabel (tlbl);
10870 outBitAcc (result);
10873 freeAsmop (left, NULL);
10874 freeAsmop (right, NULL);
10875 freeAsmop (result, NULL);
10878 /*-----------------------------------------------------------------*/
10879 /* genOrOp - for || operation */
10880 /*-----------------------------------------------------------------*/
10881 static void
10882 genOrOp (const iCode * ic)
10884 operand *left, *right, *result;
10886 /* note here that || operations that are in an
10887 if statement are taken away by backPatchLabels
10888 only those used in arthmetic operations remain */
10889 aopOp ((left = IC_LEFT (ic)), ic, FALSE, TRUE);
10890 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, TRUE);
10891 aopOp ((result = IC_RESULT (ic)), ic, FALSE, FALSE);
10893 /* if both are bit variables */
10894 if (left->aop->type == AOP_CRY && right->aop->type == AOP_CRY)
10896 wassertl (0, "Tried to OR two bits");
10898 else
10900 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
10901 _toBoolean (left, TRUE);
10902 if (!regalloc_dry_run)
10903 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
10904 regalloc_dry_run_cost += 3;
10905 _toBoolean (right, FALSE);
10906 if (!regalloc_dry_run)
10907 emitLabel (tlbl);
10908 outBitAcc (result);
10911 freeAsmop (left, NULL);
10912 freeAsmop (right, NULL);
10913 freeAsmop (result, NULL);
10916 /*-----------------------------------------------------------------*/
10917 /* isLiteralBit - test if lit == 2^n */
10918 /*-----------------------------------------------------------------*/
10919 static int
10920 isLiteralBit (unsigned long lit)
10922 unsigned long pw[32] =
10924 1L, 2L, 4L, 8L, 16L, 32L, 64L, 128L,
10925 0x100L, 0x200L, 0x400L, 0x800L,
10926 0x1000L, 0x2000L, 0x4000L, 0x8000L,
10927 0x10000L, 0x20000L, 0x40000L, 0x80000L,
10928 0x100000L, 0x200000L, 0x400000L, 0x800000L,
10929 0x1000000L, 0x2000000L, 0x4000000L, 0x8000000L,
10930 0x10000000L, 0x20000000L, 0x40000000L, 0x80000000L
10932 int idx;
10934 for (idx = 0; idx < 32; idx++)
10935 if (lit == pw[idx])
10936 return idx;
10937 return -1;
10940 /*-----------------------------------------------------------------*/
10941 /* jmpTrueOrFalse - */
10942 /*-----------------------------------------------------------------*/
10943 static void
10944 jmpTrueOrFalse (iCode * ic, symbol * tlbl)
10946 // ugly but optimized by peephole
10947 // Using emitLabelSpill instead of emitLabel (esp. on sm83)
10948 // We could jump there from locations with different values in hl.
10949 // This should be changed to a more efficient solution that spills
10950 // only what and when necessary.
10951 if (IC_TRUE (ic))
10953 if (!regalloc_dry_run)
10955 symbol *nlbl = newiTempLabel (NULL);
10956 emit2 ("jp !tlabel", labelKey2num (nlbl->key));
10957 emitLabelSpill (tlbl);
10958 emit2 ("jp !tlabel", labelKey2num (IC_TRUE (ic)->key));
10959 emitLabelSpill (nlbl);
10961 regalloc_dry_run_cost += 6;
10963 else
10965 if (!regalloc_dry_run)
10967 emit2 ("jp !tlabel", labelKey2num (IC_FALSE (ic)->key));
10968 emitLabelSpill (tlbl);
10970 regalloc_dry_run_cost += 3;
10974 /*-----------------------------------------------------------------*/
10975 /* genAnd - code for and */
10976 /*-----------------------------------------------------------------*/
10977 static void
10978 genAnd (const iCode * ic, iCode * ifx)
10980 operand *left, *right, *result;
10981 int size, offset = 0;
10982 unsigned long long lit = 0L;
10983 unsigned int bytelit = 0;
10985 aopOp ((left = IC_LEFT (ic)), ic, FALSE, FALSE);
10986 aopOp ((right = IC_RIGHT (ic)), ic, FALSE, FALSE);
10987 aopOp ((result = IC_RESULT (ic)), ic, TRUE, FALSE);
10989 bool pushed_a = false;
10990 bool a_free = isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] <= 0 && right->aop->regs[A_IDX] <= 0;
10992 /* if left is a literal & right is not then exchange them */
10993 if ((left->aop->type == AOP_LIT && right->aop->type != AOP_LIT) || (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
10995 operand *tmp = right;
10996 right = left;
10997 left = tmp;
11000 /* if result = right then exchange them */
11001 if (sameRegs (result->aop, right->aop) && !AOP_NEEDSACC (left))
11003 operand *tmp = right;
11004 right = left;
11005 left = tmp;
11008 if (right->aop->type == AOP_LIT)
11009 lit = ullFromVal (right->aop->aopu.aop_lit);
11011 size = result->aop->size;
11013 if (left->aop->type == AOP_CRY)
11015 wassertl (0, "Tried to perform an AND with a bit as an operand");
11016 goto release;
11019 /* Make sure A is on the left to not overwrite it. */
11020 if (aopInReg (right->aop, 0, A_IDX) ||
11021 !aopInReg (left->aop, 0, A_IDX) && isPair (right->aop) && (getPairId (right->aop) == PAIR_HL || getPairId (right->aop) == PAIR_IY))
11023 operand *tmp = right;
11024 right = left;
11025 left = tmp;
11028 // if(val & 0xZZ) - size = 0, ifx != FALSE -
11029 // bit = val & 0xZZ - size = 1, ifx = FALSE -
11030 if ((right->aop->type == AOP_LIT) && (result->aop->type == AOP_CRY) && (left->aop->type != AOP_CRY))
11032 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
11033 int sizel;
11035 sizel = left->aop->size;
11036 if (size)
11038 /* PENDING: Test case for this. */
11039 emit2 ("scf");
11040 cost2 (1, 4, 3, 2, 4, 2, 1, 1);
11042 while (sizel)
11044 char *jumpcond = "NZ";
11046 if ((bytelit = ((lit >> (offset * 8)) & 0x0ffull)) == 0x00ull)
11048 sizel--;
11049 offset++;
11050 continue;
11053 /* Testing for the border bits of the accumulator destructively is cheap. */
11054 if ((isLiteralBit (bytelit) == 0 || isLiteralBit (bytelit) == 7) && aopInReg (left->aop, offset, A_IDX) && isRegDead (A_IDX, ic))
11056 emit3 (isLiteralBit (bytelit) == 0 ? A_RRCA : A_RLCA, 0 , 0);
11057 jumpcond = "C";
11058 sizel--;
11059 offset++;
11061 /* Testing for the inverse of the border bits of some 32-bit registers destructively is cheap. */
11062 /* More combinations would be possible, but this one is the one that is common in the floating-point library. */
11063 else if (left->aop->type == AOP_REG && sizel >= 4 && ((lit >> (offset * 8)) & 0xffffffffull) == 0x7fffffffull &&
11064 !IS_SM83 && getPartPairId (left->aop, offset) == PAIR_HL && isPairDead (PAIR_HL, ic) &&
11065 IS_RAB && getPartPairId (left->aop, offset + 2) == PAIR_DE && isPairDead (PAIR_HL, ic))
11067 emit3 (A_CP, ASMOP_A, ASMOP_A); // Clear carry.
11068 emit3w (A_ADC, ASMOP_HL, ASMOP_HL); // Cannot use "add hl, hl instead, since it does not affect zero flag.
11069 if (!regalloc_dry_run)
11070 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
11071 emit2 ("rl de");
11072 regalloc_dry_run_cost += 6;
11073 sizel -= 4;
11074 offset += 4;
11076 /* Testing for the inverse of the border bits of some 16-bit registers destructively is cheap. */
11077 /* More combinations would be possible, but these are the common ones. */
11078 else if (left->aop->type == AOP_REG && sizel >= 2 && ((lit >> (offset * 8)) & 0xffffull) == 0x7fffull &&
11079 (!IS_SM83 && getPartPairId (left->aop, offset) == PAIR_HL && isPairDead (PAIR_HL, ic) ||
11080 IS_RAB && getPartPairId (left->aop, offset) == PAIR_DE && isPairDead (PAIR_DE, ic)))
11082 PAIR_ID pair;
11083 switch (left->aop->aopu.aop_reg[offset]->rIdx)
11085 case L_IDX:
11086 case H_IDX:
11087 pair = PAIR_HL;
11088 break;
11089 case E_IDX:
11090 case D_IDX:
11091 pair = PAIR_DE;
11092 break;
11093 default:
11094 pair = PAIR_INVALID;
11095 wassertl (0, "Invalid pair");
11097 emit3 (A_CP, ASMOP_A, ASMOP_A); // Clear carry.
11098 if (pair == PAIR_HL)
11100 emit2 ("adc %s, %s", _pairs[pair].name, _pairs[pair].name); // Cannot use add hl, hl instead, since it does not affect zero flag.
11101 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
11103 else
11105 emit2 ("rl %s", _pairs[pair].name);
11106 cost (1, 2);
11108 sizel -= 2;
11109 offset += 2;
11111 /* Testing for the border bits of some 16-bit registers destructively is cheap. */
11112 else if (left->aop->type == AOP_REG && sizel == 1 &&
11113 (isLiteralBit (bytelit) == 7 && (
11114 left->aop->aopu.aop_reg[offset]->rIdx == H_IDX && isPairDead (PAIR_HL, ic) ||
11115 IS_RAB && left->aop->aopu.aop_reg[offset]->rIdx == D_IDX && isPairDead (PAIR_DE, ic) ||
11116 left->aop->aopu.aop_reg[offset]->rIdx == IYH_IDX && isPairDead (PAIR_IY, ic)
11117 ) ||
11118 isLiteralBit (bytelit) == 0 && IS_RAB && (
11119 left->aop->aopu.aop_reg[offset]->rIdx == L_IDX && isPairDead (PAIR_HL, ic) ||
11120 left->aop->aopu.aop_reg[offset]->rIdx == E_IDX && isPairDead (PAIR_DE, ic) ||
11121 left->aop->aopu.aop_reg[offset]->rIdx == IYL_IDX && isPairDead (PAIR_IY, ic)
11124 PAIR_ID pair;
11125 switch (left->aop->aopu.aop_reg[offset]->rIdx)
11127 case L_IDX:
11128 case H_IDX:
11129 pair = PAIR_HL;
11130 break;
11131 case E_IDX:
11132 case D_IDX:
11133 pair = PAIR_DE;
11134 break;
11135 case IYL_IDX:
11136 case IYH_IDX:
11137 pair = PAIR_IY;
11138 break;
11139 default:
11140 pair = PAIR_INVALID;
11141 wassertl (0, "Invalid pair");
11143 if ((pair == PAIR_HL || pair == PAIR_IY) && isLiteralBit (bytelit) == 7)
11145 emit2 ("add %s, %s", _pairs[pair].name, _pairs[pair].name);
11146 if (pair == PAIR_HL)
11147 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
11148 else
11149 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
11151 else if (isLiteralBit (bytelit) == 7)
11153 emit2 ("rl %s", _pairs[pair].name);
11154 cost (1, 2);
11156 else
11158 emit2 ("rr %s", _pairs[pair].name);
11159 cost (1, 2);
11161 jumpcond = "C";
11162 sizel--;
11163 offset++;
11165 /* Non-destructive and when exactly one bit per byte is set. */
11166 else if (isLiteralBit (bytelit) >= 0 &&
11167 (left->aop->type == AOP_STK || aopInReg (left->aop, offset, A_IDX) || left->aop->type == AOP_HL || left->aop->type == AOP_IY ||
11168 left->aop->type == AOP_REG && !aopInReg (left->aop, offset, IYL_IDX) && !aopInReg (left->aop, offset, IYH_IDX)))
11170 if (requiresHL (left->aop) && left->aop->type != AOP_REG)
11171 _push (PAIR_HL);
11172 if (!regalloc_dry_run)
11173 emit2 ("bit %d, %s", isLiteralBit (bytelit), aopGet (left->aop, offset, FALSE));
11174 if (left->aop->type == AOP_REG)
11175 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
11176 else
11177 cost2 (4, 20 , 15, 10, 6, 10, 5, 5);
11178 if (requiresHL (left->aop) && left->aop->type != AOP_REG)
11179 _pop (PAIR_HL);
11180 sizel--;
11181 offset++;
11183 /* Z180 has non-destructive and. */
11184 else if ((IS_Z180 || IS_EZ80_Z80 || IS_Z80N) && aopInReg (left->aop, 0, A_IDX) && !isRegDead (A_IDX, ic) && bytelit != 0x0ff)
11186 if (!regalloc_dry_run)
11187 emit2 ("tst a, %s", aopGet (right->aop, 0, FALSE));
11188 cost2 (3, 11, 9, 0, 0, 0, 3, 0);
11189 sizel--;
11190 offset++;
11192 else if (!isRegDead (A_IDX, ic) && bytelit == 0x0ff && !aopInReg (left->aop, offset, A_IDX) && left->aop->type == AOP_REG && !aopInReg (left->aop, offset, IYL_IDX) && !aopInReg (left->aop, offset, IYH_IDX))
11194 emit3_o (A_RLC, left->aop, offset, 0, 0);
11195 emit3_o (A_RRC, left->aop, offset, 0, 0);
11196 sizel--;
11197 offset++;
11199 /* Generic case, loading into accumulator and testing there. */
11200 else
11202 if (!isRegDead (A_IDX, ic) || left->aop->regs[A_IDX] > offset || right->aop->regs[A_IDX] > offset)
11203 UNIMPLEMENTED;
11205 cheapMove (ASMOP_A, 0, left->aop, offset, true);
11206 if (isLiteralBit (bytelit) == 0 || isLiteralBit (bytelit) == 7)
11208 emit3 (isLiteralBit (bytelit) == 0 ? A_RRCA : A_RLCA, 0 , 0);
11209 jumpcond = "C";
11211 else if (bytelit != 0xffu)
11212 emit3_o (A_AND, ASMOP_A, 0, right->aop, offset);
11213 else
11214 emit3 (A_OR, ASMOP_A, ASMOP_A); /* For the flags */
11215 sizel--;
11216 offset++;
11218 if (size || ifx) /* emit jmp only, if it is actually used */
11220 if (!regalloc_dry_run)
11221 emit2 ("jp %s, !tlabel", jumpcond, labelKey2num (tlbl->key));
11222 regalloc_dry_run_cost += 3;
11225 // bit = left & literal
11226 if (size)
11228 emit2 ("clr c");
11229 if (!regalloc_dry_run)
11230 emit2 ("!tlabeldef", labelKey2num (tlbl->key));
11231 regalloc_dry_run_cost += 3;
11232 genLine.lineCurr->isLabel = 1;
11234 // if(left & literal)
11235 else
11237 if (ifx)
11238 jmpTrueOrFalse (ifx, tlbl);
11239 goto release;
11241 outBitC (result);
11242 goto release;
11245 if ((IS_RAB || IS_TLCS90) && isPair (result->aop) &&
11246 (getPairId (result->aop) == PAIR_HL && isPair (right->aop) && getPairId (right->aop) == PAIR_DE ||
11247 getPairId (result->aop) == PAIR_HL && isPair (left->aop) && getPairId (left->aop) == PAIR_DE))
11249 if (isPair (left->aop) && getPairId (left->aop) == PAIR_DE)
11250 fetchPair (PAIR_HL, right->aop);
11251 else // right operand in DE
11252 fetchPair (getPairId (result->aop), left->aop);
11253 emit2 ("and hl, de");
11254 cost2 (1 + IS_TLCS90, 0, 0, 2, 0, 8, 0, 0);
11255 goto release;
11258 wassertl (result->aop->type != AOP_CRY, "Result of and is in a bit");
11260 for (int i = 0; i < size;)
11262 bool hl_free = isPairDead (PAIR_HL, ic) &&
11263 (left->aop->regs[L_IDX] < i && left->aop->regs[H_IDX] < i && right->aop->regs[L_IDX] < i && right->aop->regs[H_IDX] < i) &&
11264 (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= i) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= i);
11266 if (isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] <= i && right->aop->regs[A_IDX] <= i && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= i))
11267 a_free = true;
11269 if (pushed_a && (aopInReg (left->aop, i, A_IDX) || aopInReg (right->aop, i, A_IDX)))
11271 _pop (PAIR_AF);
11272 if (!isRegDead (A_IDX, ic))
11273 _push (PAIR_AF);
11274 else
11275 pushed_a = false;
11278 if (aopIsLitVal (result->aop, i, 1, 0x00) || aopIsLitVal (right->aop, i, 1, 0x00) || aopIsLitVal (right->aop, i, 1, 0xff))
11280 unsigned int bytelit = (aopIsLitVal (result->aop, i, 1, 0x00) || aopIsLitVal (right->aop, i, 1, 0x00)) ? 0x00 : 0xff;
11282 int end;
11283 for(end = i; end < size && (!bytelit && aopIsLitVal (result->aop, end, 1, 0x00) || aopIsLitVal (right->aop, end, 1, bytelit)); end++);
11284 genMove_o (result->aop, i, bytelit == 0x00 ? ASMOP_ZERO : left->aop, i, end - i, a_free, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11285 if (result->aop->regs[A_IDX] >= i && result->aop->regs[A_IDX] < end)
11286 a_free = false;
11287 i = end;
11288 continue;
11291 if (right->aop->type == AOP_LIT)
11293 bytelit = byteOfVal (right->aop->aopu.aop_lit, i);
11295 if (isLiteralBit (~bytelit & 0xffu) >= 0 && aopSame (result->aop, i, left->aop, i, 1) &&
11296 (result->aop->type == AOP_STK || result->aop->type == AOP_DIR || result->aop->type == AOP_REG && !aopInReg (result->aop, i, IYL_IDX) && !aopInReg (result->aop, i, IYH_IDX)))
11298 cheapMove (result->aop, i, left->aop, i, a_free);
11299 if (!regalloc_dry_run)
11300 emit2 ("res %d, %s", isLiteralBit (~bytelit & 0xffu), aopGet (result->aop, i, false));
11301 if (result->aop->type == AOP_STK && !IS_SM83)
11302 cost2 (4, 23, 19, 13, 0, 14, 5, 7); // res b, d(ix)
11303 else if (result->aop->type == AOP_DIR)
11304 cost2 (2, 15, 13, 10, 16, 10, 3 , 5); // res b, (hl)
11305 else
11306 cost2 (2, 8, 6, 4, 8, 4, 2, 2); // res b, r
11307 if (aopInReg (result->aop, i, A_IDX))
11308 a_free = false;
11309 i++;
11310 continue;
11312 else if (IS_RAB &&
11313 (aopInReg (result->aop, i, HL_IDX) && (aopInReg (left->aop, i, HL_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, DE_IDX)) ||
11314 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))))
11316 unsigned int 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));
11317 bool mask_in_de = (aopInReg (left->aop, i, L_IDX) || aopInReg (left->aop, i, H_IDX));
11318 emit2 (mask_in_de ? "ld de, !immedword" : "ld hl, !immedword", mask);
11319 emit2 ("and hl, de");
11320 cost2 (1 + IS_TLCS90, 0, 0, 2, 0, 8, 0, 0);
11321 i += 2;
11322 continue;
11324 else if (IS_TLCS90 &&
11325 (aopInReg (left->aop, i, HL_IDX) && aopInReg (result->aop, i, HL_IDX) || aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i + 1, L_IDX) && aopInReg (result->aop, i, H_IDX) && aopInReg (result->aop, i + 1, L_IDX)))
11327 unsigned int 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));
11328 emit2 ("and hl, !immedword", mask);
11329 cost (3, 6);
11330 i += 2;
11331 continue;
11335 if (IS_RAB || IS_TLCS90)
11337 const bool this_byte_l = aopInReg (result->aop, i, L_IDX) &&
11338 (aopInReg (left->aop, i, L_IDX) && aopInReg (right->aop, i, E_IDX) || aopInReg (left->aop, i, E_IDX) && aopInReg (right->aop, i, L_IDX));
11339 const bool this_byte_h = aopInReg (result->aop, i, H_IDX) &&
11340 (aopInReg (left->aop, i, H_IDX) && aopInReg (right->aop, i, D_IDX) || aopInReg (left->aop, i, D_IDX) && aopInReg (right->aop, i, H_IDX));
11341 const bool next_byte_l = aopInReg (result->aop, i + 1, L_IDX) &&
11342 (aopInReg (left->aop, i + 1, L_IDX) && aopInReg (right->aop, i + 1, E_IDX) || aopInReg (left->aop, i + 1, E_IDX) && aopInReg (right->aop, i + 1, L_IDX));
11343 const bool next_byte_h = aopInReg (result->aop, i + 1, H_IDX) &&
11344 (aopInReg (left->aop, i + 1, H_IDX) && aopInReg (right->aop, i + 1, D_IDX) || aopInReg (left->aop, i + 1, D_IDX) && aopInReg (right->aop, i + 1, H_IDX));
11346 const bool this_byte = this_byte_l || this_byte_h;
11347 const bool next_byte = next_byte_l || next_byte_h;
11349 const int next_byte_idx = this_byte_l ? H_IDX : L_IDX;
11350 const bool next_byte_unused = isRegDead (next_byte_idx, ic) &&
11351 left->aop->regs[next_byte_idx] <= i && right->aop->regs[next_byte_idx] <= i &&
11352 (result->aop->regs[next_byte_idx] < 0 || result->aop->regs[next_byte_idx] >= i);
11354 if (this_byte && (next_byte || next_byte_unused))
11356 emit2 ("and hl, de");
11357 cost2 (1 + IS_TLCS90, 0, 0, 2, 0, 8, 0, 0);
11358 i += (1 + next_byte);
11359 continue;
11363 if (!a_free)
11365 if (pushed_a)
11366 UNIMPLEMENTED;
11367 else
11368 _push (PAIR_AF);
11369 pushed_a = true;
11370 a_free = true;
11373 // Use plain and in a.
11374 if (aopInReg (right->aop, i, A_IDX))
11376 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11377 _push (PAIR_HL);
11378 if (!HAS_IYL_INST && (aopInReg (left->aop, i, IYL_IDX) || aopInReg (left->aop, i, IYH_IDX)))
11379 UNIMPLEMENTED;
11380 else
11381 emit3_o (A_AND, ASMOP_A, 0, left->aop, i);
11382 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11383 _pop (PAIR_HL);
11385 else
11387 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11388 _push (PAIR_HL);
11389 cheapMove (ASMOP_A, 0, left->aop, i, true);
11390 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11391 _pop (PAIR_HL);
11393 if (requiresHL (right->aop) && right->aop->type != AOP_REG && !hl_free)
11394 _push (PAIR_HL);
11396 if ((right->aop->type == AOP_SFR || (aopInReg (right->aop, i, IYL_IDX) || aopInReg (right->aop, i, IYH_IDX)) && !HAS_IYL_INST) && hl_free)
11398 cheapMove (ASMOP_L, 0, left->aop, i, false);
11399 emit3 (A_AND, ASMOP_A, ASMOP_L);
11401 else if (right->aop->type == AOP_SFR || !HAS_IYL_INST && (aopInReg (right->aop, i, IYL_IDX) || aopInReg (right->aop, i, IYH_IDX)))
11402 UNIMPLEMENTED;
11403 else
11404 emit3_o (A_AND, ASMOP_A, 0, right->aop, i);
11405 if (requiresHL (right->aop) && right->aop->type != AOP_REG && !hl_free)
11406 _pop (PAIR_HL);
11409 hl_free = isPairDead (PAIR_HL, ic) &&
11410 (left->aop->regs[L_IDX] <= i && left->aop->regs[H_IDX] <= i && right->aop->regs[L_IDX] <= i && right->aop->regs[H_IDX] <= i) &&
11411 (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= i) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= i);
11413 genMove_o (result->aop, i, ASMOP_A, 0, 1, true, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11415 if (aopInReg (result->aop, i, A_IDX))
11416 a_free = false;
11418 i++;
11420 if (pushed_a)
11421 _pop (PAIR_AF);
11423 release:
11424 freeAsmop (left, NULL);
11425 freeAsmop (right, NULL);
11426 freeAsmop (result, NULL);
11429 /*-----------------------------------------------------------------*/
11430 /* genOr - code for or */
11431 /*-----------------------------------------------------------------*/
11432 static void
11433 genOr (const iCode * ic, iCode * ifx)
11435 operand *left, *right, *result;
11436 int size, offset = 0;
11437 unsigned long long lit = 0;
11439 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
11440 aopOp (IC_RIGHT (ic), ic, FALSE, FALSE);
11441 aopOp (IC_RESULT (ic), ic, TRUE, FALSE);
11443 left = IC_LEFT (ic);
11444 right = IC_RIGHT (ic);
11445 result = IC_RESULT (ic);
11447 if (result->aop->type == AOP_REG && left->aop->type != AOP_REG && right->aop->type != AOP_REG)
11449 if (!requiresHL (right->aop) || (result->aop->regs[L_IDX] < 0 && result->aop->regs[H_IDX] < 0))
11450 { /* only if not (right requires HL and result use HL) */
11451 genMove (result->aop, left->aop,
11452 isRegDead (A_IDX, ic),
11453 isPairDead (PAIR_HL, ic),
11454 isPairDead (PAIR_DE, ic) && right->aop->regs[D_IDX] < 0 && right->aop->regs[E_IDX] < 0,
11455 true);
11456 left = result;
11461 bool pushed_a = false;
11462 bool a_free = isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] <= 0 && right->aop->regs[A_IDX] <= 0;
11464 /* if left is a literal & right is not then exchange them */
11465 if ((left->aop->type == AOP_LIT && right->aop->type != AOP_LIT) || (AOP_NEEDSACC (right) && !AOP_NEEDSACC (left)))
11467 operand *tmp = right;
11468 right = left;
11469 left = tmp;
11472 /* if result = right then exchange them */
11473 if (sameRegs (result->aop, right->aop) && !AOP_NEEDSACC (left))
11475 operand *tmp = right;
11476 right = left;
11477 left = tmp;
11480 if (right->aop->type == AOP_LIT)
11481 lit = ullFromVal (right->aop->aopu.aop_lit);
11483 size = result->aop->size;
11485 if (left->aop->type == AOP_CRY)
11487 wassertl (0, "Tried to OR where left is a bit");
11488 goto release;
11491 /* Make sure A is on the left to not overwrite it. */
11492 if (aopInReg (right->aop, 0, A_IDX))
11494 operand *tmp = right;
11495 right = left;
11496 left = tmp;
11499 // if(val | 0xZZ) - size = 0, ifx != FALSE -
11500 // bit = val | 0xZZ - size = 1, ifx = FALSE -
11501 if ((right->aop->type == AOP_LIT) && (result->aop->type == AOP_CRY) && (left->aop->type != AOP_CRY))
11503 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
11504 int sizel;
11506 sizel = left->aop->size;
11508 if (size)
11510 wassertl (0, "Result is assigned to a bit");
11512 /* PENDING: Modeled after the AND code which is inefficient. */
11513 while (sizel--)
11515 if (isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] <= offset && right->aop->regs[A_IDX] <= offset && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= offset))
11516 a_free = true;
11518 if (!a_free) // Hard to handle pop with ifx
11519 UNIMPLEMENTED;
11521 int bytelit = (lit >> (offset * 8)) & 0x0FFull;
11523 cheapMove (ASMOP_A, 0, left->aop, offset, true);
11525 if (bytelit != 0)
11526 emit3_o (A_OR, ASMOP_A, 0, right->aop, offset);
11527 else if (ifx)
11529 /* For the flags */
11530 emit3 (A_OR, ASMOP_A, ASMOP_A);
11533 if (ifx) /* emit jmp only, if it is actually used */
11535 if (!regalloc_dry_run)
11536 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
11537 regalloc_dry_run_cost += 3;
11540 offset++;
11542 if (ifx)
11544 jmpTrueOrFalse (ifx, tlbl);
11546 goto release;
11549 wassertl (result->aop->type != AOP_CRY, "Result of or is in a bit");
11551 for (int i = 0; i < size;)
11553 bool hl_free = isPairDead (PAIR_HL, ic) &&
11554 (left->aop->regs[L_IDX] < i && left->aop->regs[H_IDX] < i && right->aop->regs[L_IDX] < i && right->aop->regs[H_IDX] < i) &&
11555 (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= i) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= i);
11557 if (isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] <= i && right->aop->regs[A_IDX] <= i && (result->aop->regs[A_IDX] < 0 || result->aop->regs[A_IDX] >= i))
11558 a_free = true;
11560 if (pushed_a && (aopInReg (left->aop, i, A_IDX) || aopInReg (right->aop, i, A_IDX)))
11562 _pop (PAIR_AF);
11563 if (!isRegDead (A_IDX, ic))
11564 _push (PAIR_AF);
11565 else
11566 pushed_a = false;
11569 if (left->aop->type == AOP_REG && right->aop->type == AOP_REG && // Try to use ld (nn), rr, etc.
11570 aopIsLitVal (left->aop, i, 1, 0x00) && aopIsLitVal (right->aop, i + 1, 1, 0x00) &&
11571 (aopInReg (right->aop, i, C_IDX) && aopInReg (left->aop, i + 1, B_IDX) || aopInReg (right->aop, i, E_IDX) && aopInReg (left->aop, i + 1, D_IDX) || aopInReg (right->aop, i, L_IDX) && aopInReg (left->aop, i + 1, H_IDX) || aopInReg (right->aop, i, IYL_IDX) && aopInReg (left->aop, i + 1, IYH_IDX)))
11573 asmop *source = aopInReg (right->aop, i, C_IDX) ? ASMOP_BC : aopInReg (right->aop, i, E_IDX) ? ASMOP_DE : aopInReg (right->aop, i, L_IDX) ? ASMOP_HL : ASMOP_IY;
11574 genMove_o (result->aop, i, source, 0, 2, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic), true);
11575 i += 2;
11576 continue;
11578 else if (left->aop->type == AOP_REG && right->aop->type == AOP_REG && // Try to use ld (nn), rr, etc.
11579 aopIsLitVal (left->aop, i + 1, 1, 0x00) && aopIsLitVal (right->aop, i, 1, 0x00) &&
11580 (aopInReg (right->aop, i + 1, B_IDX) && aopInReg (left->aop, i, C_IDX) || aopInReg (right->aop, i + 1, D_IDX) && aopInReg (left->aop, i, E_IDX) || aopInReg (right->aop, i + 1, H_IDX) && aopInReg (left->aop, i, L_IDX) || aopInReg (right->aop, i + 1, IYH_IDX) && aopInReg (left->aop, i, IYL_IDX)) &&
11581 (result->aop->type == AOP_DIR ||result->aop->type == AOP_HL || result->aop->type == AOP_IY))
11583 asmop *source = aopInReg (right->aop, i + 1, B_IDX) ? ASMOP_BC : aopInReg (right->aop, i + 1, D_IDX) ? ASMOP_DE : aopInReg (right->aop, i + 1, H_IDX) ? ASMOP_HL : ASMOP_IY;
11584 genMove_o (result->aop, i, source, 0, 2, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic), true);
11585 i += 2;
11586 continue;
11588 else if (aopIsLitVal (left->aop, i, 1, 0x00) && !pushed_a)
11590 int end;
11591 for(end = i; end < size && aopIsLitVal (left->aop, end, 1, 0x00); end++);
11592 genMove_o (result->aop, i, right->aop, i, end - i, a_free, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11593 if (result->aop->regs[A_IDX] >= i && result->aop->regs[A_IDX] < end)
11594 a_free = false;
11595 i = end;
11596 continue;
11598 else if (aopIsLitVal (right->aop, i, 1, 0x00) && !pushed_a)
11600 int end;
11601 for(end = i; end < size && aopIsLitVal (right->aop, end, 1, 0x00); end++);
11602 genMove_o (result->aop, i, left->aop, i, end - i, a_free, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11603 if (result->aop->regs[A_IDX] >= i && result->aop->regs[A_IDX] < end)
11604 a_free = false;
11605 i = end;
11606 continue;
11608 else if (aopIsLitVal (left->aop, i, 1, 0xff) || aopIsLitVal (right->aop, i, 1, 0xff))
11610 int end;
11611 for(end = i; end < size && (aopIsLitVal (left->aop, end, 1, 0xff) || aopIsLitVal (right->aop, end, 1, 0xff)); end++);
11612 genMove_o (result->aop, i, ASMOP_MONE, i, end - i, a_free, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11613 if (result->aop->regs[A_IDX] >= i && result->aop->regs[A_IDX] < end)
11614 a_free = false;
11615 i = end;
11616 continue;
11619 if (right->aop->type == AOP_LIT)
11621 int bytelit = byteOfVal (right->aop->aopu.aop_lit, i);
11623 if (isLiteralBit (bytelit) >= 0 && aopSame (result->aop, i, left->aop, i, 1) &&
11624 (result->aop->type == AOP_STK || result->aop->type == AOP_DIR || result->aop->type == AOP_REG && !aopInReg (result->aop, i, IYL_IDX) && !aopInReg (result->aop, i, IYH_IDX)))
11626 cheapMove (result->aop, i, left->aop, i, a_free);
11627 if (!regalloc_dry_run)
11628 emit2 ("set %d, %s", isLiteralBit (bytelit), aopGet (result->aop, i, false));
11629 if (result->aop->type == AOP_STK && !IS_SM83)
11630 cost2 (4, 23, 19, 13, 0, 14, 5, 7); // set b, d(ix)
11631 else if (result->aop->type == AOP_DIR)
11632 cost2 (2, 15, 13, 10, 16, 10, 3 , 5); // set b, (hl)
11633 else
11634 cost2 (2, 8, 6, 4, 8, 4, 2, 2); // set b, r
11635 if (aopInReg (result->aop, i, A_IDX))
11636 a_free = false;
11637 i++;
11638 continue;
11640 else if (IS_RAB &&
11641 (aopInReg (result->aop, i, HL_IDX) && (aopInReg (left->aop, i, HL_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, DE_IDX)) ||
11642 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))))
11644 unsigned int 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));
11645 bool mask_in_de = (aopInReg (left->aop, i, L_IDX) || aopInReg (left->aop, i, H_IDX));
11646 emit2 (mask_in_de ? "ld de, !immedword" : "ld hl, !immedword", mask);
11647 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
11648 emit2 ("or hl, de");
11649 cost2 (1, 0, 0 , 2, 0, 8, 0, 0);
11650 i += 2;
11651 continue;
11653 else if (IS_RAB &&
11654 (aopInReg (result->aop, i, IY_IDX) && (aopInReg (left->aop, i, IY_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, DE_IDX)) ||
11655 aopInReg (result->aop, i, IYH_IDX) && aopInReg (result->aop, i + 1, IYL_IDX) && (aopInReg (left->aop, i, IYH_IDX) && aopInReg (left->aop, i + 1, IYL_IDX) && !isPairInUse (PAIR_DE, ic) || aopInReg (left->aop, i, D_IDX) && aopInReg (left->aop, i + 1, E_IDX))))
11657 unsigned int mask = aopInReg (result->aop, i, IYL_IDX) ? (bytelit + (byteOfVal (right->aop->aopu.aop_lit, i + 1) << 8)) : (byteOfVal (right->aop->aopu.aop_lit, i + 1) + (bytelit << 8));
11658 bool mask_in_de = (aopInReg (left->aop, i, IYL_IDX) || aopInReg (left->aop, i, IYH_IDX));
11659 emit2 (mask_in_de ? "ld de, !immedword" : "ld iy, !immedword", mask);
11660 cost (3 + !mask_in_de, 6 + 2 * !mask_in_de);
11661 emit2 ("or iy, de");
11662 cost (2, 4);
11663 i += 2;
11664 continue;
11666 else if (IS_TLCS90 &&
11667 (aopInReg (left->aop, i, HL_IDX) && aopInReg (result->aop, i, HL_IDX) || aopInReg (left->aop, i, H_IDX) && aopInReg (left->aop, i + 1, L_IDX) && aopInReg (result->aop, i, H_IDX) && aopInReg (result->aop, i + 1, L_IDX)))
11669 unsigned int 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));
11670 emit2 ("or hl, !immedword", mask);
11671 cost (3, 6);
11672 i += 2;
11673 continue;
11677 if (IS_RAB)
11679 const bool this_byte_l = aopInReg (result->aop, i, L_IDX) &&
11680 (aopInReg (left->aop, i, L_IDX) && aopInReg (right->aop, i, E_IDX) || aopInReg (left->aop, i, E_IDX) && aopInReg (right->aop, i, L_IDX));
11681 const bool this_byte_h = aopInReg (result->aop, i, H_IDX) &&
11682 (aopInReg (left->aop, i, H_IDX) && aopInReg (right->aop, i, D_IDX) || aopInReg (left->aop, i, D_IDX) && aopInReg (right->aop, i, H_IDX));
11683 const bool next_byte_l = aopInReg (result->aop, i + 1, L_IDX) &&
11684 (aopInReg (left->aop, i + 1, L_IDX) && aopInReg (right->aop, i + 1, E_IDX) || aopInReg (left->aop, i + 1, E_IDX) && aopInReg (right->aop, i + 1, L_IDX));
11685 const bool next_byte_h = aopInReg (result->aop, i + 1, H_IDX) &&
11686 (aopInReg (left->aop, i + 1, H_IDX) && aopInReg (right->aop, i + 1, D_IDX) || aopInReg (left->aop, i + 1, D_IDX) && aopInReg (right->aop, i + 1, H_IDX));
11688 const bool this_byte_hl = this_byte_l || this_byte_h;
11689 const bool next_byte_hl = next_byte_l || next_byte_h;
11691 const int next_byte_hl_idx = this_byte_l ? H_IDX : L_IDX;
11692 const bool next_byte_hl_unused = isRegDead (next_byte_hl_idx, ic) &&
11693 left->aop->regs[next_byte_hl_idx] <= i && right->aop->regs[next_byte_hl_idx] <= i &&
11694 (result->aop->regs[next_byte_hl_idx] < 0 || result->aop->regs[next_byte_hl_idx] >= i);
11696 if (this_byte_hl && (next_byte_hl || next_byte_hl_unused))
11698 emit2 ("or hl, de");
11699 cost2 (1, 0, 0 , 2, 0, 8, 0, 0);
11700 i += (1 + next_byte_hl);
11701 continue;
11704 if (aopInReg (result->aop, i, IY_IDX) &&
11705 (aopInReg (left->aop, i, IY_IDX) && aopInReg (right->aop, i, DE_IDX) || aopInReg (left->aop, i, DE_IDX) && aopInReg (right->aop, i, IY_IDX)))
11707 emit2 ("or iy, de");
11708 cost (2, 4);
11709 i += 2;
11710 continue;
11712 else if (aopInReg (right->aop, i, DE_IDX) &&
11713 (left->aop->type == AOP_STK || left->aop->type == AOP_DIR || left->aop->type == AOP_IY) &&
11714 (aopInReg (result->aop, i, HL_IDX) || isPairDead(PAIR_HL, ic) && right->aop->regs[L_IDX] < i + 2 && right->aop->regs[H_IDX] < i + 2 && (result->aop->type == AOP_DIR || result->aop->type == AOP_IY || result->aop->type == AOP_STK)))
11716 fetchPairLong (PAIR_HL, left->aop, ic, i);
11717 emit2 ("or hl, de");
11718 cost2 (1, 0, 0 , 2, 0, 8, 0, 0);
11719 genMove_o (result->aop, i, ASMOP_HL, 0, 2, a_free, true, false, true, true);
11720 i += 2;
11721 continue;
11725 // Use plain or in a.
11726 if (!a_free)
11728 wassert (!pushed_a);
11729 _push (PAIR_AF);
11730 pushed_a = true;
11731 a_free = true;
11734 if (aopInReg (right->aop, i, A_IDX) || right->aop->type == AOP_SFR ||
11735 !HAS_IYL_INST && (aopInReg (right->aop, i, IYL_IDX) || aopInReg (right->aop, i, IYH_IDX)))
11737 cheapMove (ASMOP_A, 0, right->aop, i, true);
11739 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11740 _push (PAIR_HL);
11741 if ((left->aop->type == AOP_SFR || (aopInReg (right->aop, i, IYL_IDX) || aopInReg (right->aop, i, IYH_IDX)) && !HAS_IYL_INST) && hl_free)
11743 cheapMove (ASMOP_L, 0, left->aop, i, false);
11744 emit3 (A_OR, ASMOP_A, ASMOP_L);
11746 else if (left->aop->type == AOP_SFR || aopInReg (right->aop, i, A_IDX) ||
11747 !HAS_IYL_INST && (aopInReg (right->aop, i, IYL_IDX) || aopInReg (right->aop, i, IYH_IDX)))
11748 UNIMPLEMENTED;
11749 else
11750 emit3_o (A_OR, ASMOP_A, 0, left->aop, i);
11751 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11752 _pop (PAIR_HL);
11754 else
11756 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11757 _push (PAIR_HL);
11758 cheapMove (ASMOP_A, 0, left->aop, i, true);
11759 if (requiresHL (left->aop) && left->aop->type != AOP_REG && !hl_free)
11760 _pop (PAIR_HL);
11762 if (requiresHL (right->aop) && right->aop->type != AOP_REG && !hl_free)
11763 _push (PAIR_HL);
11764 emit3_o (A_OR, ASMOP_A, 0, right->aop, i);
11765 if (requiresHL (right->aop) && right->aop->type != AOP_REG && !hl_free)
11766 _pop (PAIR_HL);
11769 hl_free = isPairDead (PAIR_HL, ic) &&
11770 (left->aop->regs[L_IDX] <= i && left->aop->regs[H_IDX] <= i && right->aop->regs[L_IDX] <= i && right->aop->regs[H_IDX] <= i) &&
11771 (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= i) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= i);
11773 genMove_o (result->aop, i, ASMOP_A, 0, 1, true, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11775 if (aopInReg (result->aop, i, A_IDX))
11776 a_free = false;
11777 i++;
11780 if (pushed_a)
11781 _pop (PAIR_AF);
11783 release:
11784 freeAsmop (IC_LEFT (ic), NULL);
11785 freeAsmop (IC_RIGHT (ic), NULL);
11786 freeAsmop (IC_RESULT (ic), NULL);
11789 /*-----------------------------------------------------------------*/
11790 /* genEor - code for xclusive or */
11791 /*-----------------------------------------------------------------*/
11792 static void
11793 genEor (const iCode *ic, iCode *ifx, asmop *result_aop, asmop *left_aop, asmop *right_aop)
11795 int size;
11796 bool pushed_a = false;
11798 bool a_free = isRegDead (A_IDX, ic) && left_aop->regs[A_IDX] <= 0 && right_aop->regs[A_IDX] <= 0;
11800 /* if left is a literal & right is not then exchange them */
11801 if ((left_aop->type == AOP_LIT && right_aop->type != AOP_LIT) || ((right_aop->type == AOP_SFR || right_aop->type == AOP_CRY) && !(left_aop->type == AOP_SFR || left_aop->type == AOP_CRY)))
11803 asmop *taop = right_aop;
11804 right_aop = left_aop;
11805 left_aop = taop;
11808 /* if result = right then exchange them */
11809 if (sameRegs (result_aop, right_aop) && !(left_aop->type == AOP_SFR || left_aop->type == AOP_CRY))
11811 asmop *taop = right_aop;
11812 right_aop = left_aop;
11813 left_aop = taop;
11816 size = result_aop->size;
11818 if (left_aop->type == AOP_CRY)
11820 wassertl (0, "Tried to XOR a bit");
11821 return;
11824 /* Make sure A is on the left to not overwrite it. */
11825 if (aopInReg (right_aop, 0, A_IDX))
11827 wassert (!(left_aop->type == AOP_SFR || left_aop->type == AOP_CRY));
11828 asmop *taop = right_aop;
11829 right_aop = left_aop;
11830 left_aop = taop;
11833 // if(val & 0xZZ) - size = 0, ifx != FALSE -
11834 // bit = val & 0xZZ - size = 1, ifx = FALSE -
11835 if ((right_aop->type == AOP_LIT) && (result_aop->type == AOP_CRY) && (left_aop->type != AOP_CRY))
11837 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
11838 int offset = 0;
11839 int sizel = left_aop->size;
11841 if (size)
11843 /* PENDING: Test case for this. */
11844 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
11846 while (sizel--)
11848 if (isRegDead (A_IDX, ic) && left_aop->regs[A_IDX] <= offset && right_aop->regs[A_IDX] <= offset && (result_aop->regs[A_IDX] < 0 || result_aop->regs[A_IDX] >= offset))
11849 a_free = true;
11851 if (!a_free)
11853 wassert (!pushed_a);
11854 _push (PAIR_AF);
11855 a_free = true;
11856 pushed_a = true;
11857 if (ifx) // The pop at the end is hard to deal with in case of ifx.
11858 UNIMPLEMENTED;
11860 else if (pushed_a && (aopInReg (left_aop, offset, A_IDX) || aopInReg (right_aop, offset, A_IDX)))
11862 _pop (PAIR_AF);
11863 if (!isRegDead (A_IDX, ic))
11864 _push (PAIR_AF);
11865 else
11866 pushed_a = false;
11869 if (aopInReg (right_aop, offset, A_IDX))
11870 emit3_o (A_XOR, ASMOP_A, 0, left_aop, offset);
11871 else
11873 cheapMove (ASMOP_A, 0, left_aop, offset, true);
11874 emit3_o (A_XOR, ASMOP_A, 0, right_aop, offset);
11876 if (ifx) /* emit jmp only, if it is actually used * */
11877 if (!regalloc_dry_run)
11878 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
11879 regalloc_dry_run_cost += 3;
11880 offset++;
11882 if (pushed_a)
11884 _pop (PAIR_AF);
11885 pushed_a = false;
11887 if (ifx)
11889 jmpTrueOrFalse (ifx, tlbl);
11891 else if (size)
11893 wassertl (0, "Result of XOR was destined for a bit");
11895 return;
11898 // left & result in different registers
11899 if (result_aop->type == AOP_CRY)
11901 wassertl (0, "Result of XOR is in a bit");
11902 return;
11905 for (int i = 0; i < size;)
11907 bool hl_free = isPairDead (PAIR_HL, ic) &&
11908 (left_aop->regs[L_IDX] < i && left_aop->regs[H_IDX] < i && right_aop->regs[L_IDX] < i && right_aop->regs[H_IDX] < i) &&
11909 (result_aop->regs[L_IDX] < 0 || result_aop->regs[L_IDX] >= i) && (result_aop->regs[H_IDX] < 0 || result_aop->regs[H_IDX] >= i);
11911 if (isRegDead (A_IDX, ic) && left_aop->regs[A_IDX] <= i && right_aop->regs[A_IDX] <= i && (result_aop->regs[A_IDX] < 0 || result_aop->regs[A_IDX] >= i))
11912 a_free = true;
11914 // normal case
11915 // result = left ^ right
11916 if (aopIsLitVal (right_aop, i, 1, 0x00))
11918 int end;
11919 for (end = i; end < size && aopIsLitVal (right_aop, end, 1, 0x00); end++);
11920 if (pushed_a && left_aop->type == AOP_REG && left_aop->regs[A_IDX] >= i && left_aop->regs[A_IDX] < end)
11922 if (result_aop->regs[A_IDX] >= 0 && result_aop->regs[A_IDX] < i)
11923 UNIMPLEMENTED;
11924 _pop (PAIR_AF);
11925 if (!isRegDead (A_IDX, ic))
11926 _push (PAIR_AF);
11927 else
11928 pushed_a = false;
11930 genMove_o (result_aop, i, left_aop, i, end - i, a_free, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
11931 if (result_aop->type == AOP_REG &&
11932 (left_aop->regs[result_aop->aopu.aop_reg[i]->rIdx] >= end || right_aop->regs[result_aop->aopu.aop_reg[i]->rIdx] >= end))
11933 UNIMPLEMENTED;
11934 if (result_aop->regs[A_IDX] >= i && result_aop->regs[A_IDX] < end)
11935 a_free = false;
11936 i = end;
11937 continue;
11939 else if (IS_TLCS90 && right_aop->type == AOP_LIT &&
11940 (aopInReg (left_aop, i, HL_IDX) && aopInReg (result_aop, i, HL_IDX) || aopInReg (left_aop, i, H_IDX) && aopInReg (left_aop, i + 1, L_IDX) && aopInReg (result_aop, i, H_IDX) && aopInReg (result_aop, i + 1, L_IDX)))
11942 unsigned int bytelit = byteOfVal (right_aop->aopu.aop_lit, i);
11943 unsigned int 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));
11944 emit2 ("xor hl, !immedword", mask);
11945 cost (3, 6);
11946 i += 2;
11947 continue;
11949 else if (IS_RAB && aopIsLitVal (right_aop, i, 1, 0x01) &&
11950 (aopInReg (left_aop, i, L_IDX) && aopInReg (result_aop, i, L_IDX) || aopInReg (left_aop, i, E_IDX) && aopInReg (result_aop, i, E_IDX)))
11952 bool de = aopInReg (result_aop, i, E_IDX);
11953 emit2 (de ? "rr de" : "rr hl");
11954 cost (1, 2);
11955 emit2 ("ccf");
11956 cost (1, 2);
11957 emit2 (de ? "rl de" : "adc hl, hl");
11958 cost (2 - de, 4 - 2 * de);
11959 i++;
11960 continue;
11962 else if (IS_RAB && aopIsLitVal (right_aop, i, 1, 0x80) &&
11963 (aopInReg (left_aop, i, H_IDX) && aopInReg (result_aop, i, H_IDX) || aopInReg (left_aop, i, D_IDX) && aopInReg (result_aop, i, D_IDX)))
11965 bool de = aopInReg (result_aop, i, D_IDX);
11966 emit2 (de ? "rl de" : "add hl, hl");
11967 cost (1, 2);
11968 emit2 ("ccf");
11969 cost (1, 2);
11970 emit2 (de ? "rr de" : "rr hl");
11971 cost (1, 2);
11972 i++;
11973 continue;
11976 if (pushed_a && (aopInReg (left_aop, i, A_IDX) || aopInReg (right_aop, i, A_IDX)))
11978 if (result_aop->regs[A_IDX] >= 0 && result_aop->regs[A_IDX] < i)
11979 UNIMPLEMENTED;
11980 _pop (PAIR_AF);
11981 if (!isRegDead (A_IDX, ic))
11982 _push (PAIR_AF);
11983 else
11984 pushed_a = false;
11987 // faster than result <- left, anl result,right
11988 // and better if result is SFR
11989 if (!a_free)
11991 if (pushed_a)
11992 UNIMPLEMENTED;
11993 else
11994 _push (PAIR_AF);
11995 a_free = true;
11996 pushed_a = true;
11999 if (aopInReg (right_aop, i, A_IDX) && left_aop->type != AOP_STL)
12001 if (requiresHL (left_aop) && left_aop->type != AOP_REG && !hl_free)
12002 _push (PAIR_HL);
12003 if (!HAS_IYL_INST && (aopInReg (left_aop, i, IYL_IDX) || aopInReg (left_aop, i, IYH_IDX)))
12004 UNIMPLEMENTED;
12005 else
12006 emit3_o (A_XOR, ASMOP_A, 0, left_aop, i);
12007 if (requiresHL (left_aop) && left_aop->type != AOP_REG && !hl_free)
12008 _pop (PAIR_HL);
12010 else
12012 if (requiresHL (left_aop) && left_aop->type != AOP_REG && !hl_free)
12013 _push (PAIR_HL);
12014 cheapMove (ASMOP_A, 0, left_aop, i, true);
12015 if (requiresHL (left_aop) && left_aop->type != AOP_REG && !hl_free)
12016 _pop (PAIR_HL);
12017 if (right_aop->type == AOP_LIT && byteOfVal (right_aop->aopu.aop_lit, i) == 0xff)
12018 emit3 (A_CPL, 0, 0);
12019 else if (right_aop->type == AOP_SFR || right_aop->type == AOP_STL || aopInReg (right_aop, i, IYL_IDX) || aopInReg (right_aop, i, IYH_IDX))
12021 if (!hl_free)
12022 _push (PAIR_HL);
12023 cheapMove (ASMOP_L, 0, right_aop, i, false);
12024 emit3_o (A_XOR, ASMOP_A, 0, ASMOP_L, 0);
12025 if (!hl_free)
12026 _pop (PAIR_HL);
12028 else
12030 if (requiresHL (right_aop) && right_aop->type != AOP_REG && !hl_free)
12031 _push (PAIR_HL);
12032 emit3_o (A_XOR, ASMOP_A, 0, right_aop, i);
12033 if (requiresHL (right_aop) && right_aop->type != AOP_REG && !hl_free)
12034 _pop (PAIR_HL);
12038 hl_free = isPairDead (PAIR_HL, ic) &&
12039 (left_aop->regs[L_IDX] <= i && left_aop->regs[H_IDX] <= i && right_aop->regs[L_IDX] <= i && right_aop->regs[H_IDX] <= i) &&
12040 (result_aop->regs[L_IDX] < 0 || result_aop->regs[L_IDX] >= i) && (result_aop->regs[H_IDX] < 0 || result_aop->regs[H_IDX] >= i);
12042 genMove_o (result_aop, i, ASMOP_A, 0, 1, true, hl_free, !isPairInUse (PAIR_DE, ic), true, true);
12044 if(result_aop->type == AOP_REG &&
12045 (left_aop->regs[result_aop->aopu.aop_reg[i]->rIdx] > i || right_aop->regs[result_aop->aopu.aop_reg[i]->rIdx] > i))
12046 UNIMPLEMENTED;
12047 if (aopInReg (result_aop, i, A_IDX))
12048 a_free = false;
12050 i++;
12053 if (pushed_a)
12054 _pop (PAIR_AF);
12057 /*-----------------------------------------------------------------*/
12058 /* genXor - code for exclusive or */
12059 /*-----------------------------------------------------------------*/
12060 static void
12061 genXor (const iCode *ic, iCode *ifx)
12063 aopOp (IC_LEFT (ic), ic, false, false);
12064 aopOp (IC_RIGHT (ic), ic, false, false);
12065 aopOp (IC_RESULT (ic), ic, true, false);
12067 genEor (ic, ifx, IC_RESULT (ic)->aop, IC_LEFT (ic)->aop, IC_RIGHT (ic)->aop);
12069 freeAsmop (IC_LEFT (ic), NULL);
12070 freeAsmop (IC_RIGHT (ic), NULL);
12071 freeAsmop (IC_RESULT (ic), NULL);
12074 /*-----------------------------------------------------------------*/
12075 /* genCpl - generate code for complement */
12076 /*-----------------------------------------------------------------*/
12077 static void
12078 genCpl (const iCode *ic)
12080 /* assign asmOps to operand & result */
12081 aopOp (IC_LEFT (ic), ic, false, false);
12082 aopOp (IC_RESULT (ic), ic, true, false);
12084 genEor (ic, 0, IC_RESULT (ic)->aop, IC_LEFT (ic)->aop, ASMOP_MONE);
12086 /* release the aops */
12087 freeAsmop (IC_LEFT (ic), 0);
12088 freeAsmop (IC_RESULT (ic), 0);
12091 /*-----------------------------------------------------------------*/
12092 /* genRRC - rotate right with carry */
12093 /*-----------------------------------------------------------------*/
12094 static void
12095 genRRC (const iCode *ic)
12097 bool pushed_a = false;
12099 operand *left = IC_LEFT (ic);
12100 operand *right = IC_RIGHT (ic);
12101 operand *result = IC_RESULT (ic);
12103 aopOp (left, ic, false, false);
12104 aopOp (result, ic, true, false);
12106 int size = result->aop->size;
12108 wassert (size >= 2); // 8-bit rotations are handled in Rot1
12109 wassert (!(bitsForType (operandType (left)) % 8));
12110 wassert (IS_OP_LITERAL (right));
12112 int s = operandLitValueUll (right) % bitsForType (operandType (left));
12114 wassert (s == bitsForType (operandType (left)) - 1);
12116 int offset = size - 1;
12118 if (IS_Z80N && size == 2 && aopInReg (result->aop, 0, DE_IDX) && isRegDead (B_IDX, ic))
12120 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, true);
12121 emit2 ("ld b, !immedbyte", 15u);
12122 cost (2, 7);
12123 emit2 ("brlc de, b");
12124 cost (2, 8);
12126 else if (left->aop->type == AOP_REG || result->aop->type == AOP_STK ||
12127 result->aop->type == AOP_HL || result->aop->type == AOP_IY ||
12128 result->aop->type == AOP_EXSTK || result->aop->type == AOP_REG)
12130 if (!isRegDead (A_IDX, ic))
12132 _push (PAIR_AF);
12133 pushed_a = true;
12135 if (left->aop->type != AOP_REG && !operandsEqu (result, left))
12137 /* always prefer register operations */
12138 genMove_o (result->aop, 0, left->aop, 0, size, true, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12139 left = result;
12141 cheapMove (ASMOP_A, 0, left->aop, offset, true);
12142 emit3_o (A_RRA, 0, 0, 0, 0);
12143 while (--offset >= 0)
12144 emit3_o (A_RR, left->aop, offset, 0, 0);
12145 if (IS_SM83 && requiresHL (left->aop))
12146 { /* ldhl sp,N changes CARRY */
12147 emit3_o (A_RRA, 0, 0, 0, 0);
12148 if (!regalloc_dry_run)
12149 aopGet (left->aop, size - 1, false);
12150 emit3_o (A_RLA, 0, 0, 0, 0);
12152 emit3_o (A_RR, left->aop, size - 1, 0, 0);
12153 if (!operandsEqu (result, left))
12154 genMove_o (result->aop, 0, left->aop, 0, size, true, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12156 else
12158 if (!isRegDead (A_IDX, ic))
12160 _push (PAIR_AF);
12161 pushed_a = true;
12163 while (offset >= 0)
12165 _moveA (aopGet (left->aop, offset, false));
12166 emit3_o (A_RRA, 0, 0, 0, 0);
12167 if (offset != size - 1)
12168 aopPut (result->aop, "a", offset);
12169 --offset;
12171 _moveA (aopGet (left->aop, size - 1, false));
12172 emit3_o (A_RRA, 0, 0, 0, 0);
12173 aopPut (result->aop, "a", size - 1);
12175 if (pushed_a)
12176 _pop (PAIR_AF);
12178 freeAsmop (IC_LEFT (ic), 0);
12179 freeAsmop (IC_RESULT (ic), 0);
12182 /*-----------------------------------------------------------------*/
12183 /* genRLC - generate code for rotate left */
12184 /*-----------------------------------------------------------------*/
12185 static void
12186 genRLC (const iCode *ic)
12188 bool pushed_a = false;
12190 operand *left = IC_LEFT (ic);
12191 operand *right = IC_RIGHT (ic);
12192 operand *result = IC_RESULT (ic);
12194 aopOp (left, ic, false, false);
12195 aopOp (result, ic, true, false);
12197 int size = result->aop->size;
12199 wassert (size >= 2); // 8-bit rotations are handled in Rot1
12200 wassert (!(bitsForType (operandType (left)) % 8));
12201 wassert (IS_OP_LITERAL (right));
12203 int s = operandLitValueUll (right) % bitsForType (operandType (left));
12205 wassert (s == 1);
12207 if (IS_Z80N && size == 2 &&
12208 (aopInReg (result->aop, 0, DE_IDX) || aopInReg (left->aop, 0, DE_IDX) && isRegDead (DE_IDX, ic)) && isRegDead (B_IDX, ic))
12210 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, isRegDead (IY_IDX, ic));
12211 emit2 ("ld b, !immedbyte", s);
12212 emit2 ("brlc de, b");
12213 cost (4, 15);
12214 genMove (result->aop, ASMOP_DE, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, isRegDead (IY_IDX, ic));
12216 else if (left->aop->type == AOP_REG || result->aop->type == AOP_STK ||
12217 result->aop->type == AOP_HL || result->aop->type == AOP_IY ||
12218 result->aop->type == AOP_EXSTK || result->aop->type == AOP_REG)
12220 asmop *rotaop = result->aop;
12221 if (!isRegDead (A_IDX, ic))
12223 _push (PAIR_AF);
12224 pushed_a = true;
12226 if (size == 2 && (aopInReg (left->aop, 0, HL_IDX) && isRegDead (HL_IDX, ic) || IS_RAB && aopInReg (left->aop, 0, DE_IDX) && isRegDead (DE_IDX, ic)))
12227 rotaop = left->aop;
12228 genMove (rotaop, left->aop, true, isRegDead (HL_IDX, ic), isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
12229 cheapMove (ASMOP_A, 0, rotaop, size - 1, true);
12230 emit3 (A_RLA, 0, 0);
12231 if (IS_SM83 && requiresHL (rotaop) && rotaop->type != AOP_REG)
12232 { /* ldhl sp,N changes CARRY */
12233 emit3_o (A_RRA, 0, 0, 0, 0);
12234 if (!regalloc_dry_run)
12235 aopGet (rotaop, 0, false);
12236 emit3_o (A_RLA, 0, 0, 0, 0);
12238 for (int i = 0; i < size;)
12240 if (!IS_SM83 && i + 1 < size && aopInReg (rotaop, i, HL_IDX))
12242 emit2 ("adc hl, hl");
12243 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
12244 i += 2;
12246 else if (IS_RAB && i + 1 < size && aopInReg (rotaop, i, DE_IDX))
12248 emit2 ("rl de");
12249 cost (1, 2);
12250 i += 2;
12252 else
12254 emit3_o (A_RL, rotaop, i, 0, 0);
12255 i++;
12258 genMove (result->aop, rotaop, true, isRegDead (HL_IDX, ic), isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
12260 else
12262 if (!isRegDead (A_IDX, ic))
12264 _push (PAIR_AF);
12265 pushed_a = true;
12268 for (int offset = 0; offset < size; ++offset)
12270 _moveA (aopGet (left->aop, offset, false));
12271 emit3_o (A_RLA, 0, 0, 0, 0);
12272 if (offset != 0)
12273 aopPut (result->aop, "a", offset);
12275 _moveA (aopGet (left->aop, 0, false));
12276 emit3_o (A_RLA, 0, 0, 0, 0);
12277 aopPut (result->aop, "a", 0);
12280 if (pushed_a)
12281 _pop (PAIR_AF);
12283 freeAsmop (IC_LEFT (ic), 0);
12284 freeAsmop (IC_RESULT (ic), 0);
12287 /*-----------------------------------------------------------------*/
12288 /* genGetByte - generates code to get a single byte */
12289 /*-----------------------------------------------------------------*/
12290 static void
12291 genGetByte (const iCode *ic)
12293 operand *left, *right, *result;
12294 int offset;
12296 left = IC_LEFT (ic);
12297 right = IC_RIGHT (ic);
12298 result = IC_RESULT (ic);
12299 aopOp (left, ic, FALSE, FALSE);
12300 aopOp (right, ic, FALSE, FALSE);
12301 aopOp (result, ic, TRUE, FALSE);
12303 offset = (int) ulFromVal (right->aop->aopu.aop_lit) / 8;
12304 genMove_o (result->aop, 0, left->aop, offset, 1, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12306 freeAsmop (result, NULL);
12307 freeAsmop (right, NULL);
12308 freeAsmop (left, NULL);
12311 /*-----------------------------------------------------------------*/
12312 /* genGetWord - generates code to get a 16-bit word */
12313 /*-----------------------------------------------------------------*/
12314 static void
12315 genGetWord (const iCode *ic)
12317 operand *left, *right, *result;
12318 int offset;
12320 left = IC_LEFT (ic);
12321 right = IC_RIGHT (ic);
12322 result = IC_RESULT (ic);
12323 aopOp (left, ic, FALSE, FALSE);
12324 aopOp (right, ic, FALSE, FALSE);
12325 aopOp (result, ic, TRUE, FALSE);
12327 offset = (int) ulFromVal (right->aop->aopu.aop_lit) / 8;
12328 genMove_o (result->aop, 0, left->aop, offset, 2, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12330 freeAsmop (result, NULL);
12331 freeAsmop (right, NULL);
12332 freeAsmop (left, NULL);
12335 /*-----------------------------------------------------------------*/
12336 /* genGetAbit - generates code get a single bit */
12337 /*-----------------------------------------------------------------*/
12338 static void
12339 genGetAbit (const iCode * ic)
12341 operand *left, *right, *result;
12342 int shCount;
12344 left = IC_LEFT (ic);
12345 right = IC_RIGHT (ic);
12346 result = IC_RESULT (ic);
12347 aopOp (left, ic, FALSE, FALSE);
12348 aopOp (right, ic, FALSE, FALSE);
12349 aopOp (result, ic, TRUE, FALSE);
12351 shCount = (int) ulFromVal (right->aop->aopu.aop_lit);
12353 /* get the needed byte into a */
12354 cheapMove (ASMOP_A, 0, left->aop, shCount / 8, true);
12355 shCount %= 8;
12356 if (shCount == 4 && (IS_SM83 || IS_Z80N))
12358 emit3_o (A_SWAP, ASMOP_A, 0, 0, 0);
12359 shCount -= 4;
12361 if (result->aop->type == AOP_CRY)
12364 if (shCount < 4)
12365 while (shCount-- >= 0)
12366 emit3_o (A_RRCA, 0, 0, 0, 0);
12367 else
12368 while (shCount++ < 8)
12369 emit3_o (A_RLCA, 0, 0, 0, 0);
12370 outBitC (result);
12372 else
12374 if (shCount < 5)
12375 while (shCount-- > 0)
12376 emit3_o (A_RRCA, 0, 0, 0, 0);
12377 else
12378 while (shCount++ < 8)
12379 emit3_o (A_RLCA, 0, 0, 0, 0);
12380 emit2 ("and a, !immedbyte", 0x01u);
12381 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
12382 outAcc (result);
12385 freeAsmop (result, NULL);
12386 freeAsmop (right, NULL);
12387 freeAsmop (left, NULL);
12390 static void
12391 emitRsh2 (asmop * aop, int size, int is_signed)
12393 int offset = 0;
12395 while (size--)
12397 if (offset == 0)
12398 emit3_o (is_signed ? A_SRA : A_SRL, aop, size, 0, 0);
12399 else
12400 emit3_o (A_RR, aop, size, 0, 0);
12401 offset++;
12405 /*-----------------------------------------------------------------*/
12406 /* shiftR2Left2Result - shift right two bytes from left to result */
12407 /*-----------------------------------------------------------------*/
12408 static void
12409 shiftR2Left2Result (const iCode *ic, operand *left, int offl, operand *result, int offr, int shCount, int is_signed)
12411 int size = 2;
12412 symbol *tlbl;
12414 if (IS_RAB && !is_signed && shCount < 4 &&
12415 (getPairId (result->aop) == PAIR_HL || getPairId (result->aop) == PAIR_DE))
12417 bool op_de = (getPairId (result->aop) == PAIR_DE);
12418 fetchPairLong (getPairId (result->aop), left->aop, ic, offl);
12419 while (shCount--)
12421 emit3 (A_CP, ASMOP_A, ASMOP_A);
12422 cost (1, 2);
12423 emit2 (op_de? "rr de" : "rr hl");
12424 cost (1, 2);
12426 return;
12428 else if (!IS_SM83 && !IS_RAB && !is_signed && aopSame (result->aop, offr, left->aop, offl, 2) && isPairDead (PAIR_HL, ic) && isRegDead (A_IDX, ic) &&
12429 (shCount == 4 || shCount == 5) &&
12430 (result->aop->type == AOP_DIR || result->aop->type == AOP_HL || result->aop->type == AOP_IY))
12432 emit2 ("xor a, a");
12433 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
12434 emit2 ("ld hl, !hashedstr+1", result->aop->aopu.aop_dir);
12435 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
12436 emit3 (A_RRD, 0, 0);
12437 if (shCount == 5)
12439 emit2 ("srl (hl)");
12440 cost2 (2, 15, 6, 10, 16, 8, 5, 5);
12442 emit2 ("dec hl");
12443 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
12444 emit3 (A_RRD, 0, 0);
12445 if (shCount == 5)
12447 emit2 ("rr (hl)");
12448 cost2 (2, 15, 6, 10, 16, 8, 5, 5);
12450 return;
12452 else if (IS_RAB && !is_signed && shCount >= 2 && isPairDead (PAIR_HL, ic) &&
12453 ((isPair (left->aop) && getPairId (left->aop) == PAIR_HL || isPair (result->aop)
12454 && getPairId (result->aop) == PAIR_HL) && isPairDead (PAIR_DE, ic) || isPair (left->aop)
12455 && getPairId (left->aop) == PAIR_DE))
12457 bool op_de = (getPairId (left->aop) == PAIR_DE);
12458 if (op_de)
12459 emit2 ("ld hl, !immedword", 0xffffu >> shCount);
12460 else
12462 fetchPair (PAIR_HL, left->aop);
12463 emit2 ("ld de, !immedword", 0xffffu >> shCount);
12465 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
12466 while (shCount--)
12468 emit2 (op_de ? "rr de" : "rr hl");
12469 cost (1, 2);
12471 emit2 ("and hl, de");
12472 cost (1, 2);
12473 genMove (IC_RESULT (ic)->aop, ASMOP_HL, true, true, isPairDead (PAIR_DE, ic), true);
12474 return;
12476 else if ((getPairId (result->aop) == PAIR_HL || getPairId (left->aop) == PAIR_HL) && isPairDead (PAIR_HL, ic) &&
12477 shCount == 7 && is_signed)
12479 tlbl = regalloc_dry_run ? 0 : newiTempLabel (NULL);
12480 genMove (ASMOP_HL, left->aop, isRegDead (A_IDX, ic), true, isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
12481 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
12482 emit3 (A_LD, ASMOP_L, ASMOP_H);
12483 emit3 (A_LD, ASMOP_H, ASMOP_ZERO);
12484 if (!regalloc_dry_run)
12485 emit2 ("jr nc,!tlabel", labelKey2num (tlbl->key));
12486 emit2 ("dec h");
12487 if (!regalloc_dry_run)
12488 emitLabel (tlbl);
12489 cost (3, 11.5f);
12490 genMove (result->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isRegDead (DE_IDX, ic), isRegDead (IY_IDX, ic));
12491 return;
12493 // If the leading bits are all the same, we can shift the other way, and use efficient 16-bit addition for shifts.
12494 else if (shCount < 8 &&
12495 aopInReg (left->aop, 0, HL_IDX) && aopInReg (result->aop, 0, H_IDX) && isRegDead (L_IDX, ic) && isRegDead (A_IDX, ic) &&
12496 shCount >= 5 - !optimize.codeSpeed) // Smaller code size for 4 and above, but at least for Z80(N), only faster from 5.
12498 emit3 (A_XOR, ASMOP_A, ASMOP_A);
12499 emit2 ("add hl, hl");
12500 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
12501 if (is_signed && (left->aop->valinfo.anything || left->aop->valinfo.min < 0))
12503 tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
12504 if (!regalloc_dry_run)
12505 emit2 ("jr nc,!tlabel", labelKey2num (tlbl->key));
12506 emit2 ("dec a");
12507 cost2 (3, 11.5, 9.0, 7.0, 12.0, 7.0, 3.0, 3.0);
12508 if (!regalloc_dry_run)
12509 emitLabel (tlbl);
12511 else if (!is_signed)
12512 emit3 (A_RLA, 0, 0);
12513 for (int i = 1; i < (8 - shCount); i++)
12515 emit2 ("add hl, hl");
12516 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
12517 emit3 (A_RLA, 0, 0);
12519 genMove_o (result->aop, 1, ASMOP_A, 0, 1, true, false, isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic), true);
12520 return;
12523 if (isPair (result->aop) && !offr)
12524 fetchPairLong (getPairId (result->aop), left->aop, ic, offl);
12525 else
12526 genMove_o (result->aop, offr, left->aop, offl, 2, true, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12528 if (shCount == 0)
12529 return;
12531 /* if (result->aop->type == AOP_REG) { */
12533 /* Left is already in result - so now do the shift */
12534 /* Optimizing for speed by default. */
12535 if (!optimize.codeSize || shCount <= 2)
12537 while (shCount--)
12538 emitRsh2 (result->aop, size, is_signed);
12540 else
12542 bool use_b = (!IS_SM83 && isRegDead (B_IDX, ic)
12543 && !(result->aop->type == AOP_REG
12544 && (result->aop->aopu.aop_reg[0]->rIdx == B_IDX || result->aop->aopu.aop_reg[1]->rIdx == B_IDX)));
12546 tlbl = regalloc_dry_run ? 0 : newiTempLabel (NULL);
12548 if (requiresHL (result->aop))
12549 spillPair (PAIR_HL);
12551 emit2 ("ld %s, !immedbyte", use_b ? "b" : "a", (unsigned)shCount);
12552 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
12554 regalloc_dry_run_state_scale *= (unsigned)shCount;
12556 if (!regalloc_dry_run)
12557 emitLabel (tlbl);
12559 emitRsh2 (result->aop, size, is_signed);
12561 if (use_b)
12563 if (!regalloc_dry_run)
12564 emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
12565 cost2 (2, 13, 9, 5, 0, 10, 4, 2); // Assume jump taken.
12567 else
12569 emit3 (A_DEC, ASMOP_A, 0);
12570 if (!regalloc_dry_run)
12571 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
12572 cost2 (2, 12, 8, 5, 12, 8, 3, 3); // Assume jump taken, and optimized to jr.
12575 regalloc_dry_run_state_scale = 1.0f;
12579 /*-----------------------------------------------------------------*/
12580 /* shiftL2Left2Result - shift left two bytes from left to result */
12581 /*-----------------------------------------------------------------*/
12582 static void
12583 shiftL2Left2Result (operand *left, operand *result, int shCount, const iCode *ic)
12585 asmop *shiftaop = result->aop;
12587 if (shCount == 7 && aopIsLitVal (left->aop, 1, 1, 0x00) && result->aop->type == AOP_REG &&
12588 result->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && result->aop->aopu.aop_reg[1]->rIdx != IYL_IDX && result->aop->aopu.aop_reg[0]->rIdx != IYH_IDX && result->aop->aopu.aop_reg[1]->rIdx != IYH_IDX)
12590 genMove_o (result->aop, 1, left->aop, 0, 1, isRegDead(A_IDX, ic), false, false, false, true);
12591 bool reuse_zero = left->aop->type == AOP_REG && !aopInReg (left->aop, 1, IYL_IDX) && !aopInReg (left->aop, 1, IYH_IDX) && !aopInReg (left->aop, 1, result->aop->aopu.aop_reg[1]->rIdx);
12592 genMove_o (result->aop, 0, reuse_zero ? left->aop : ASMOP_ZERO, 1, 1, isRegDead(A_IDX, ic) && !aopInReg (result->aop, 1, A_IDX), false, false, false, true);
12593 emit3_o (A_SRL, result->aop, 1, 0, 0);
12594 if (aopInReg (result->aop, 0, A_IDX))
12595 emit3 (A_RRA, 0, 0);
12596 else
12597 emit3 (A_RR, result->aop, 0);
12598 return;
12600 /* For a shift of 7 we can use cheaper right shifts */
12601 else if (shCount == 7 && left->aop->type == AOP_REG && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[0]->rIdx) && result->aop->type == AOP_REG &&
12602 left->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && left->aop->aopu.aop_reg[1]->rIdx != IYL_IDX && left->aop->aopu.aop_reg[0]->rIdx != IYH_IDX && left->aop->aopu.aop_reg[1]->rIdx != IYH_IDX &&
12603 result->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && result->aop->aopu.aop_reg[1]->rIdx != IYL_IDX && result->aop->aopu.aop_reg[0]->rIdx != IYH_IDX && result->aop->aopu.aop_reg[1]->rIdx != IYH_IDX &&
12604 (optimize.codeSpeed || getPairId (result->aop) != PAIR_HL || getPairId (left->aop) != PAIR_HL)) /* but a sequence of add hl, hl might still be cheaper code-size wise */
12606 // Handling the low byte in A with xor clearing is cheaper.
12607 bool special_a = (isRegDead (A_IDX, ic) && !aopInReg (left->aop, 0, A_IDX) && !aopInReg (left->aop, 1, A_IDX));
12608 asmop *lowbyte = special_a ? ASMOP_A : result->aop;
12610 if (special_a)
12611 emit3 (A_XOR, ASMOP_A, ASMOP_A);
12612 emit3_o (A_RR, left->aop, 1, 0, 0);
12613 emit3_o (A_LD, result->aop, 1, left->aop, 0);
12614 emit3_o (A_RR, result->aop, 1, 0, 0);
12615 if (!special_a)
12616 emit3_o (A_LD, result->aop, 0, ASMOP_ZERO, 0);
12617 if (aopInReg (lowbyte, 0, A_IDX))
12618 emit3 (A_RRA, 0, 0);
12619 else
12620 emit3 (A_RR, lowbyte, 0);
12621 if (special_a)
12622 cheapMove (result->aop, 0, lowbyte, 0, true);
12623 return;
12625 if ((result->aop->type == AOP_HL || result->aop->type == AOP_IY || IS_RAB && result->aop->type == AOP_STK) && // Being able to use cheap add hl, hl is worth it in most cases.
12626 (left->aop->type == AOP_HL || left->aop->type == AOP_IY || IS_RAB && left->aop->type == AOP_STK) &&
12627 !IS_SM83 && isPairDead (PAIR_HL, ic) &&
12628 (shCount > 1 || !sameRegs (result->aop, left->aop)) ||
12629 isPairDead (PAIR_HL, ic) && !IS_SM83 && getPairId (result->aop) == PAIR_DE && getPairId (left->aop) != PAIR_DE) // Shift in hl if we can cheaply move to de via ex later.
12631 shiftaop = ASMOP_HL;
12632 genMove (ASMOP_HL, left->aop, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), true);
12634 else if (result->aop->type != AOP_REG && left->aop->type == AOP_REG && left->aop->size >= 2 && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[0]->rIdx) && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[1]->rIdx) ||
12635 getPairId (left->aop) == PAIR_HL && isPairDead (PAIR_HL, ic))
12636 shiftaop = left->aop;
12637 else
12638 genMove_o (result->aop, 0, left->aop, 0, 2, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12640 if (shCount == 0)
12642 else if (getPairId (shiftaop) == PAIR_HL)
12644 while (shCount--)
12645 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
12647 else if (getPairId (shiftaop) == PAIR_IY)
12649 while (shCount--)
12651 emit2 ("add iy, iy");
12652 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
12655 else if (IS_RAB && getPairId (shiftaop) == PAIR_DE && shCount <= 2 + optimize.codeSpeed)
12657 while (shCount--)
12659 emit3 (A_CP, ASMOP_A, ASMOP_A);
12660 emit2 ("rl de");
12661 cost (1, 2);
12664 else if (!IS_SM83 && getPairId (shiftaop) == PAIR_DE)
12666 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
12667 while (shCount--)
12668 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
12669 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
12671 else
12673 int size = 2;
12674 int offset = 0;
12676 bool use_b = (!IS_SM83 && isRegDead (B_IDX, ic)
12677 && (shiftaop->type != AOP_REG || shiftaop->aopu.aop_reg[0]->rIdx != B_IDX && shiftaop->aopu.aop_reg[1]->rIdx != B_IDX));
12679 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
12681 if (shiftaop->type == AOP_REG)
12683 while (shCount--)
12685 for (offset = 0; offset < size; offset++)
12686 if (aopInReg (shiftaop, offset, A_IDX))
12687 emit3 (offset ? A_ADC : A_ADD, ASMOP_A, ASMOP_A);
12688 else
12689 emit3_o (offset ? A_RL : A_SLA, shiftaop, offset, 0, 0);
12692 else
12694 if (!use_b && !isRegDead (A_IDX, ic))
12695 _push (PAIR_AF);
12697 /* Left is already in result - so now do the shift */
12698 if (shCount > 1)
12700 if (!regalloc_dry_run)
12702 emit2 ("ld %s, !immedbyte", use_b ? "b" : "a", (unsigned)shCount);
12703 emitLabel (tlbl);
12705 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
12707 if (requiresHL (shiftaop))
12708 spillPair (PAIR_HL);
12711 while (size--)
12713 emit3_o (offset ? A_RL : A_SLA, shiftaop, offset, 0, 0);
12715 offset++;
12717 if (shCount > 1)
12719 if (use_b)
12721 if (!regalloc_dry_run)
12722 emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
12723 cost2 (2, 13, 9, 5, 0, 10, 4, 2); // Assume jump taken.
12725 else
12727 emit3 (A_DEC, ASMOP_A, 0);
12728 if (!regalloc_dry_run)
12729 emit2 ("jp NZ, !tlabel", labelKey2num (tlbl->key));
12730 cost2 (2, 12, 8, 5, 12, 8, 3, 3); // Assume jump taken, and optimized to jr.
12733 if (!use_b && !isRegDead (A_IDX, ic))
12734 _pop (PAIR_AF);
12738 sym_link *resulttype = operandType (IC_RESULT (ic));
12739 unsigned topbytemask = (IS_BITINT (resulttype) && SPEC_USIGN (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
12740 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
12741 bool maskedtopbyte = (topbytemask != 0xff);
12742 if (maskedtopbyte)
12744 bool pushed_a = false;
12745 if (!isRegDead (A_IDX, ic) || shiftaop->regs[A_IDX] >= 0 && shiftaop->regs[A_IDX] != result->aop->size - 1)
12747 _push (PAIR_AF);
12748 pushed_a = true;
12750 cheapMove (ASMOP_A, 0, shiftaop, result->aop->size - 1, true);
12751 emit2 ("and a, #0x%02x", topbytemask);
12752 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
12753 cheapMove (shiftaop, result->aop->size - 1, ASMOP_A, 0, true);
12754 if (pushed_a)
12755 _pop (PAIR_AF);
12758 if (shiftaop != result->aop)
12760 if (isPair (result->aop))
12761 fetchPairLong (getPairId (result->aop), shiftaop, ic, 0);
12762 else
12763 genMove_o (result->aop, 0, shiftaop, 0, 2, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
12767 /*-----------------------------------------------------------------*/
12768 /* genSwap - generates code to swap nibbles or bytes */
12769 /*-----------------------------------------------------------------*/
12770 static void
12771 genSwap (iCode * ic)
12773 operand *left, *result;
12774 asmop swapped_result_aop;
12776 left = IC_LEFT (ic);
12777 result = IC_RESULT (ic);
12778 aopOp (left, ic, false, false);
12779 aopOp (result, ic, true, false);
12780 bool pushed_a = false;
12781 switch (left->aop->size)
12783 case 2: // swap bytes in word
12784 if (result->aop->type == AOP_REG) // Create result asmop with swapped bytes, let genMove handle the details.
12786 signed char idxarray[3];
12787 idxarray[0] = result->aop->aopu.aop_reg[1]->rIdx;
12788 idxarray[1] = result->aop->aopu.aop_reg[0]->rIdx;
12789 idxarray[2] = -1;
12790 z80_init_reg_asmop (&swapped_result_aop, idxarray);
12791 genMove (&swapped_result_aop, left->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
12792 break;
12795 if (sameRegs (result->aop, left->aop) || operandsEqu (result, left))
12797 // avoid push/pop by finding free register
12798 asmop *free_reg = ASMOP_A;
12799 if (isRegDead (B_IDX, ic))
12800 free_reg = ASMOP_B;
12801 if (isRegDead (C_IDX, ic))
12802 free_reg = ASMOP_C;
12803 if (isRegDead (D_IDX, ic))
12804 free_reg = ASMOP_D;
12805 if (isRegDead (E_IDX, ic))
12806 free_reg = ASMOP_E;
12807 cheapMove (ASMOP_A, 0, left->aop, 0, true);
12808 if (free_reg == ASMOP_A)
12810 _push (PAIR_AF);
12811 pushed_a = true;
12813 // if left and result are registers, this should get optimized away
12814 cheapMove (free_reg, 0, left->aop, 1, FALSE);
12815 cheapMove (result->aop, (free_reg == ASMOP_A ? 0 : 1), ASMOP_A, 0, FALSE);
12816 if(pushed_a){
12817 _pop (PAIR_AF);
12819 cheapMove (result->aop, (free_reg == ASMOP_A ? 1 : 0), free_reg, 0, TRUE);
12821 else
12823 cheapMove (result->aop, 0, left->aop, 1, isRegDead (A_IDX, ic) && left->aop->regs[A_IDX] != 0);
12824 cheapMove (result->aop, 1, left->aop, 0, isRegDead (A_IDX, ic) && result->aop->regs[A_IDX] != 0);
12826 break;
12828 case 4: // swap words in double word
12829 if (result->aop->type == AOP_REG) // Create result asmop with swapped words, let genMove handle the details.
12831 signed char idxarray[5];
12832 idxarray[0] = result->aop->aopu.aop_reg[2]->rIdx;
12833 idxarray[1] = result->aop->aopu.aop_reg[3]->rIdx;
12834 idxarray[2] = result->aop->aopu.aop_reg[0]->rIdx;
12835 idxarray[3] = result->aop->aopu.aop_reg[1]->rIdx;
12836 idxarray[4] = -1;
12837 z80_init_reg_asmop(&swapped_result_aop, idxarray);
12838 genMove (&swapped_result_aop, left->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
12839 break;
12841 if (operandsEqu (result, left) && left->aop->type == AOP_STK &&
12842 spOffset (left->aop->aopu.aop_stk) == 0 && isPairDead (PAIR_HL, ic) &&
12843 (!IS_SM83 || isPairDead(PAIR_DE, ic) || isPairDead(PAIR_BC, ic)))
12844 { /* result & left are top of stack and there are free register pairs */
12845 if (IS_SM83)
12847 if (isPairDead(PAIR_DE, ic))
12849 _pop (PAIR_DE);
12850 _pop (PAIR_HL);
12851 _push (PAIR_DE);
12852 _push (PAIR_HL);
12854 else
12856 _pop (PAIR_BC);
12857 _pop (PAIR_HL);
12858 _push (PAIR_BC);
12859 _push (PAIR_HL);
12862 else
12864 _pop (PAIR_HL);
12865 emit2 ("ex (sp), hl");
12866 cost2 (1 + IS_RAB, 19, 16, 15, 0, 14, 5, 5);
12867 _push (PAIR_HL);
12869 break;
12872 /* --== generic implementations ==-- */
12873 if (!operandsEqu (result, left))
12874 { /* result is registers or left differs than result */
12875 bool pushed = !isRegDead (A_IDX, ic);
12876 if (pushed)
12877 _push (PAIR_AF);
12878 cheapMove (ASMOP_A, 0, left->aop, 0, TRUE);
12879 cheapMove (result->aop, 0, left->aop, 2, FALSE);
12880 cheapMove (result->aop, 2, ASMOP_A, 0, FALSE);
12881 cheapMove (ASMOP_A, 0, left->aop, 1, TRUE);
12882 cheapMove (result->aop, 1, left->aop, 3, FALSE);
12883 cheapMove (result->aop, 3, ASMOP_A, 0, FALSE);
12884 if (pushed)
12885 _pop (PAIR_AF);
12887 else
12889 asmop *tmp = NULL;
12890 bool pushed = false;
12891 bool dead_a = isRegDead (A_IDX, ic);
12892 bool dead_de = isPairDead (PAIR_DE, ic);
12893 bool dead_hl = isPairDead (PAIR_HL, ic);
12894 if (isPairDead (PAIR_BC, ic) &&
12895 (left->aop->type != AOP_REG || !aopInReg (left->aop, 0, BC_IDX)))
12896 tmp = ASMOP_BC;
12897 else if (dead_hl &&
12898 (left->aop->type != AOP_REG || !aopInReg (left->aop, 0, HL_IDX)))
12899 tmp = ASMOP_HL;
12900 else if (dead_de &&
12901 (left->aop->type != AOP_REG || !aopInReg (left->aop, 0, DE_IDX)))
12902 tmp = ASMOP_DE;
12903 else if (!IS_SM83 && !IY_RESERVED && isPairDead (PAIR_IY, ic) &&
12904 (left->aop->type != AOP_REG || !aopInReg (left->aop, 0, IY_IDX)))
12905 tmp = ASMOP_IY;
12906 else
12908 pushed = true;
12909 if ((left->aop->type != AOP_REG || !aopInReg (left->aop, 0, HL_IDX)))
12910 tmp = ASMOP_HL;
12911 else if ((left->aop->type != AOP_REG || !aopInReg (left->aop, 0, BC_IDX)))
12912 tmp = ASMOP_BC;
12913 else if ((left->aop->type != AOP_REG || !aopInReg (left->aop, 0, DE_IDX)))
12914 tmp = ASMOP_DE;
12915 else
12916 wassertl (FALSE, "impossible case");
12917 _push (tmp->aopu.aop_pairId);
12919 genMove_o (tmp, 0, left->aop, 0, 2, dead_a, dead_hl && !aopInReg (left->aop, 2, HL_IDX), dead_de && !aopInReg (left->aop, 2, DE_IDX), true, true);
12920 genMove_o (result->aop, 0, left->aop, 2, 2, dead_a, dead_hl && (tmp != ASMOP_HL), dead_de && (tmp != ASMOP_DE), true, true);
12921 genMove_o (result->aop, 2, tmp, 0, 2, dead_a, dead_hl && !aopInReg (result->aop, 0, HL_IDX), dead_de && !aopInReg (result->aop, 0, DE_IDX), true, true);
12922 if (pushed)
12923 _pop (tmp->aopu.aop_pairId);
12925 break;
12926 default:
12927 wassertl (FALSE, "unsupported SWAP operand size");
12930 freeAsmop (result, NULL);
12931 freeAsmop (left, NULL);
12934 /*-----------------------------------------------------------------*/
12935 /* AccRol - rotate left accumulator by known count */
12936 /*-----------------------------------------------------------------*/
12937 static void
12938 AccRol (int shCount)
12940 shCount &= 0x0007; // shCount : 0..7
12942 switch (shCount)
12944 case 4:
12945 if (IS_SM83 || IS_Z80N)
12947 emit3 (A_SWAP, ASMOP_A, 0);
12948 break;
12950 emit3 (A_RLCA, 0, 0);
12951 case 3:
12952 if (IS_SM83 || IS_Z80N)
12954 emit3 (A_SWAP, ASMOP_A, 0);
12955 emit3 (A_RRCA, 0, 0);
12956 break;
12958 emit3 (A_RLCA, 0, 0);
12959 case 2:
12960 emit3 (A_RLCA, 0, 0);
12961 case 1:
12962 emit3 (A_RLCA, 0, 0);
12963 case 0:
12964 break;
12965 case 5:
12966 if (IS_SM83 || IS_Z80N)
12968 emit3 (A_SWAP, ASMOP_A, 0);
12969 emit3 (A_RLCA, 0, 0);
12970 break;
12972 emit3 (A_RRCA, 0, 0);
12973 case 6:
12974 emit3 (A_RRCA, 0, 0);
12975 case 7:
12976 emit3 (A_RRCA, 0, 0);
12977 break;
12981 /*-----------------------------------------------------------------*/
12982 /* AccLsh - left shift accumulator by known count */
12983 /*-----------------------------------------------------------------*/
12984 static void
12985 AccLsh (unsigned int shCount)
12987 static const unsigned char SLMask[] =
12989 0xFF, 0xFE, 0xFC, 0xF8, 0xF0, 0xE0, 0xC0, 0x80, 0x00
12992 if (shCount <= 3 + !IS_SM83)
12993 while (shCount--)
12994 emit3 (A_ADD, ASMOP_A, ASMOP_A);
12995 else
12997 /* rotate left accumulator */
12998 AccRol (shCount);
12999 /* and kill the lower order bits */
13000 emit2 ("and a, !immedbyte", (unsigned)(SLMask[shCount]));
13001 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13005 /*-----------------------------------------------------------------*/
13006 /* shiftL1Left2Result - shift left one byte from left to result */
13007 /*-----------------------------------------------------------------*/
13008 static void
13009 shiftL1Left2Result (operand *left, int offl, operand *result, int offr, unsigned int shCount, const iCode *ic)
13011 if (!shCount)
13012 cheapMove (result->aop, offr, left->aop, offl, isRegDead (A_IDX, ic));
13013 // add hl, hl is cheap in code size. On Rabbits it is also fastest.
13014 else if (sameRegs (result->aop, left->aop) && aopInReg (result->aop, offr, L_IDX) && isPairDead(PAIR_HL, ic) && offr == offl && (!optimize.codeSpeed && IS_RAB))
13016 while (shCount--)
13017 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
13019 else if (!IS_SM83 && !IS_RAB && aopSame (result->aop, offr, left->aop, offr, 1) && !offr && shCount == 4 && isPairDead (PAIR_HL, ic) && isRegDead (A_IDX, ic) &&
13020 (result->aop->type == AOP_DIR || result->aop->type == AOP_HL || result->aop->type == AOP_IY))
13022 emit2 ("xor a, a");
13023 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
13024 pointPairToAop (PAIR_HL, result->aop, 0);
13025 emit3 (A_RLD, 0, 0);
13027 /* If operand and result are the same we can shift in place.
13028 However shifting in acc using add is cheaper than shifting
13029 in place using sla; when shifting by more than 2 shifting in
13030 acc it is worth the additional effort for loading from / to acc. */
13031 else if (!aopInReg(result->aop, 0, A_IDX) && sameRegs (left->aop, result->aop) && shCount <= 2 && offr == offl)
13033 while (shCount--)
13034 emit3 (A_SLA, result->aop, 0);
13036 else if ((IS_Z180 && !optimize.codeSpeed || IS_EZ80_Z80 || IS_Z80N) && // Try to use mlt
13037 (!IS_Z80N && aopInReg (result->aop, offr, C_IDX) && isPairDead(PAIR_BC, ic) || aopInReg (result->aop, offr, E_IDX) && isPairDead(PAIR_DE, ic) || !IS_Z80N && aopInReg (result->aop, offr, L_IDX) && isPairDead(PAIR_HL, ic)))
13039 PAIR_ID pair = aopInReg (result->aop, offr, C_IDX) ? PAIR_BC : (aopInReg (result->aop, offr, E_IDX) ? PAIR_DE : PAIR_HL);
13041 bool top = aopInReg (left->aop, offl, _pairs[pair].h_idx);
13042 if (!top)
13043 cheapMove (pair == PAIR_BC ? ASMOP_C : (pair == PAIR_DE ? ASMOP_E : ASMOP_L), 0, left->aop, offl, isRegDead (A_IDX, ic));
13045 emit2 ("ld %s, !immed%d", top ? _pairs[pair].l : _pairs[pair].h, 1 << shCount);
13046 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
13047 emit2 ("mlt %s", _pairs[pair].name);
13048 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
13050 else
13052 if (!isRegDead (A_IDX, ic))
13053 _push (PAIR_AF);
13054 cheapMove (ASMOP_A, 0, left->aop, offl, true);
13055 /* shift left accumulator */
13056 AccLsh (shCount);
13057 cheapMove (result->aop, offr, ASMOP_A, 0, true);
13058 if (!isRegDead (A_IDX, ic))
13059 _pop (PAIR_AF);
13063 sym_link *resulttype = operandType (IC_RESULT (ic));
13064 unsigned topbytemask = (IS_BITINT (resulttype) && SPEC_USIGN (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
13065 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
13066 bool maskedtopbyte = (topbytemask != 0xff);
13067 if (maskedtopbyte)
13069 bool pushed_a = false;
13070 if (!isRegDead (A_IDX, ic) || result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] != result->aop->size - 1)
13072 _push (PAIR_AF);
13073 pushed_a = true;
13075 cheapMove (ASMOP_A, 0, result->aop, result->aop->size - 1, true);
13076 emit2 ("and a, #0x%02x", topbytemask);
13077 cost (1, 7);
13078 cheapMove (result->aop, result->aop->size - 1, ASMOP_A, 0, true);
13079 if (pushed_a)
13080 _pop (PAIR_AF);
13084 /*-----------------------------------------------------------------*/
13085 /* genlshTwo - left shift two bytes by known amount */
13086 /*-----------------------------------------------------------------*/
13087 static void
13088 genlshTwo (operand *result, operand *left, unsigned int shCount, const iCode *ic)
13090 int size = result->aop->size;
13092 wassert (size == 2);
13094 if (IS_Z80N && !operandType (result) &&
13095 aopInReg (result->aop, 0, DE_IDX) && isRegDead (B_IDX, ic) &&
13096 shCount > 2 && shCount != 8) // Only worth it when shifting by more than 2 (we can get a cheap path using add hl, hl in shiftL2Left2Result (left, result, shCount, ic)).
13098 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, true);
13099 emit2 ("ld b, !immedbyte", (unsigned)shCount);
13100 cost (2, 7);
13101 emit2 ("bsla de, b");
13102 cost (2, 8);
13104 else if (shCount >= 8)
13106 shCount -= 8;
13107 shiftL1Left2Result (left, 0, result, 1, shCount, ic);
13108 cheapMove (result->aop, 0, ASMOP_ZERO, 0, isRegDead (A_IDX, ic));
13110 else
13111 shiftL2Left2Result (left, result, shCount, ic);
13114 /*-----------------------------------------------------------------*/
13115 /* genRot1 - generates code for rotation of 8-bit values */
13116 /*-----------------------------------------------------------------*/
13117 static void
13118 genRot1 (iCode *ic)
13120 operand *left = IC_LEFT (ic);
13121 operand *right = IC_RIGHT (ic);
13122 operand *result = IC_RESULT (ic);
13124 aopOp (left, ic, false, false);
13125 aopOp (result, ic, true, false);
13127 wassert (bitsForType (operandType (left)) == 8);
13128 wassert (IS_OP_LITERAL (right));
13130 int s = operandLitValueUll (right) % 8;
13132 if (IS_SM83 && s == 4 && result->aop->type == AOP_REG)
13134 cheapMove (result->aop, 0, left->aop, 0, true);
13135 emit3 (A_SWAP, result->aop, 0);
13137 else if (IS_SM83 && s == 4 && left->aop->type == AOP_REG && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[0]->rIdx))
13139 emit3 (A_SWAP, left->aop, 0);
13140 cheapMove (result->aop, 0, left->aop, 0, true);
13142 else if ((s == 1 || s == 7) && result->aop->type == AOP_REG && !aopInReg (result->aop, 0, A_IDX) && !(aopInReg (left->aop, 0, A_IDX) && isRegDead (A_IDX, ic)))
13144 cheapMove (result->aop, 0, left->aop, 0, true);
13145 emit3 (s == 1 ? A_RLC : A_RRC, result->aop, 0);
13147 else if ((s == 1 || s == 7) && left->aop->type == AOP_REG && !bitVectBitValue (ic->rSurv, left->aop->aopu.aop_reg[0]->rIdx) && !aopInReg (left->aop, 0, A_IDX))
13149 emit3 (s == 1 ? A_RLC : A_RRC, left->aop, 0);
13150 cheapMove (result->aop, 0, left->aop, 0, true);
13152 else if (s <= 2 && aopInReg (result->aop, 0, H_IDX) && isRegDead (L_IDX, ic) && (aopInReg (left->aop, 0, H_IDX) || aopInReg (left->aop, 0, L_IDX)))
13154 if (aopInReg (left->aop, 0, H_IDX))
13155 emit3_o (A_LD, ASMOP_HL, 0, ASMOP_HL, 1);
13156 else
13157 emit3_o (A_LD, ASMOP_HL, 1, ASMOP_HL, 0);
13158 while (s--)
13159 emit3w (A_ADD, ASMOP_HL, ASMOP_HL);
13161 else if (IS_RAB && (s == 1 && aopInReg (result->aop, 0, D_IDX) && isRegDead (E_IDX, ic) || s == 7 && aopInReg (result->aop, 0, E_IDX) && isRegDead (D_IDX, ic)) &&
13162 (aopInReg (left->aop, 0, D_IDX) || aopInReg (left->aop, 0, E_IDX)))
13164 if (aopInReg (left->aop, 0, D_IDX))
13165 emit3_o (A_LD, ASMOP_DE, 0, ASMOP_DE, 1);
13166 else
13167 emit3_o (A_LD, ASMOP_DE, 1, ASMOP_DE, 0);
13168 if (s == 1)
13169 emit2 ("rl de");
13170 else
13171 emit2 ("rr de");
13172 cost (1, 2);
13174 else if (s == 4 && !IS_SM83 && !IS_RAB && (aopInReg (left->aop, 0, A_IDX) || aopSame (result->aop, 0, left->aop, 0, 1)) &&
13175 (result->aop->type == AOP_DIR || result->aop->type == AOP_HL || result->aop->type == AOP_IY) && isPairDead (PAIR_HL, ic))
13177 if (!isRegDead (A_IDX, ic))
13178 _push (PAIR_AF);
13179 if (!aopSame (result->aop, 0, left->aop, 0, 1))
13180 cheapMove (result->aop, 0, ASMOP_A, 0, false);
13181 else
13182 cheapMove (ASMOP_A, 0, result->aop, 0, true);
13183 pointPairToAop (PAIR_HL, result->aop, 0);
13184 emit3 (A_RRD, 0, 0);
13185 if (!isRegDead (A_IDX, ic))
13186 _pop (PAIR_AF);
13188 else if ((s == 1 || s == 7) && aopSame (result->aop, 0, left->aop, 0, 1) &&
13189 ((result->aop->type == AOP_EXSTK || IS_SM83 && result->aop->type == AOP_STK) || result->aop->type == AOP_DIR || result->aop->type == AOP_HL || result->aop->type == AOP_IY) && isPairDead (PAIR_HL, ic))
13191 pointPairToAop (PAIR_HL, result->aop, 0);
13192 emit2 (s == 1 ? "rlc (hl)" : "rrc (hl)");
13193 cost2 (2, 15, 13, 10, 16, 8, 5, 5);
13195 else if ((s == 1 || s == 7) && aopSame (result->aop, 0, left->aop, 0, 1) && result->aop->type == AOP_STK && !IS_SM83)
13197 emit3 (s == 1 ? A_RLC : A_RRC, result->aop, 0);
13199 else
13201 if (!isRegDead (A_IDX, ic))
13202 _push (PAIR_AF);
13203 cheapMove (ASMOP_A, 0, left->aop, 0, true);
13204 AccRol (s);
13205 cheapMove (result->aop, 0, ASMOP_A, 0, true);
13206 if (!isRegDead (A_IDX, ic))
13207 _pop (PAIR_AF);
13210 freeAsmop (left, NULL);
13211 freeAsmop (result, NULL);
13214 /*-----------------------------------------------------------------*/
13215 /* genRot - generates code for rotation */
13216 /*-----------------------------------------------------------------*/
13217 static void
13218 genRot (iCode *ic)
13220 operand *left = IC_LEFT (ic);
13221 operand *right = IC_RIGHT (ic);
13222 unsigned int lbits = bitsForType (operandType (left));
13223 if (lbits == 8 && IS_OP_LITERAL (right))
13224 genRot1 (ic);
13225 else if (IS_OP_LITERAL (right) && operandLitValueUll (right) % lbits == 1)
13226 genRLC (ic);
13227 else if (IS_OP_LITERAL (right) && operandLitValueUll (right) % lbits == lbits - 1)
13228 genRRC (ic);
13229 else if (IS_OP_LITERAL (right) && (operandLitValueUll (right) % lbits) * 2 == lbits)
13230 genSwap (ic);
13231 else
13232 wassertl (0, "Unsupported rotation.");
13235 /*------------------------------------------------------------------*/
13236 /* genLeftShiftLiteral - left shifting by known count for size <= 2 */
13237 /*------------------------------------------------------------------*/
13238 static void
13239 genLeftShiftLiteral (operand *left, operand *right, operand *result, const iCode *ic)
13241 unsigned int shCount = ulFromVal (right->aop->aopu.aop_lit);
13242 unsigned int size;
13244 freeAsmop (right, NULL);
13246 aopOp (left, ic, false, false);
13247 aopOp (result, ic, true, false);
13249 size = getSize (operandType (result));
13251 /* I suppose that the left size >= result size */
13252 wassert (getSize (operandType (left)) >= size);
13254 if (shCount >= (size * 8))
13255 genMove (result->aop, ASMOP_ZERO, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic) && left->aop->regs[H_IDX] < 0 && left->aop->regs[L_IDX] < 0, isPairDead (PAIR_DE, ic) && left->aop->regs[D_IDX] < 0 && left->aop->regs[E_IDX] < 0, true);
13256 else
13258 switch (size)
13260 case 1:
13261 shiftL1Left2Result (left, 0, result, 0, shCount, ic);
13262 break;
13263 case 2:
13264 genlshTwo (result, left, shCount, ic);
13265 break;
13266 case 4:
13267 wassertl (0, "Shifting of longs should be handled by generic function.");
13268 break;
13269 default:
13270 wassert (0);
13273 freeAsmop (left, NULL);
13274 freeAsmop (result, NULL);
13277 /*-----------------------------------------------------------------*/
13278 /* genLeftShift - generates code for left shifting */
13279 /*-----------------------------------------------------------------*/
13280 static void
13281 genLeftShift (const iCode *ic)
13283 int size, offset;
13284 symbol *tlbl = 0, *tlbl1 = 0;
13285 operand *left, *right, *result;
13286 asmop *shiftop;
13287 int countreg;
13288 bool shift_by_lit;
13289 int shiftcount = 0;
13290 int byteshift = 0;
13291 bool started;
13292 bool save_a_outer = false;
13294 right = IC_RIGHT (ic);
13295 left = IC_LEFT (ic);
13296 result = IC_RESULT (ic);
13298 aopOp (right, ic, FALSE, FALSE);
13300 /* if the shift count is known then do it
13301 as efficiently as possible */
13302 if (right->aop->type == AOP_LIT && getSize (operandType (result)) <= 2)
13304 genLeftShiftLiteral (left, right, result, ic);
13305 freeAsmop (right, NULL);
13306 return;
13309 /* Useful for the case of shifting a size > 2 value by a literal */
13310 shift_by_lit = right->aop->type == AOP_LIT;
13311 if (shift_by_lit)
13312 shiftcount = ulFromVal (right->aop->aopu.aop_lit);
13314 aopOp (result, ic, true, false);
13315 aopOp (left, ic, false, false);
13317 bool z80n_de = ((result->aop->size == 2 && (aopInReg (result->aop, 0, DE_IDX) || aopInReg (left->aop, 0, DE_IDX)) ||
13318 result->aop->size == 1 && (aopInReg (result->aop, 0, D_IDX) || aopInReg (left->aop, 0, D_IDX)))) && isRegDead (PAIR_DE, ic);
13320 if (right->aop->type == AOP_REG && !bitVectBitValue (ic->rSurv, right->aop->aopu.aop_reg[0]->rIdx) && right->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && (sameRegs (left->aop, result->aop) || left->aop->type != AOP_REG) &&
13321 (result->aop->type != AOP_REG ||
13322 result->aop->aopu.aop_reg[0]->rIdx != right->aop->aopu.aop_reg[0]->rIdx &&
13323 !aopInReg (result->aop, 0, right->aop->aopu.aop_reg[0]->rIdx) && !aopInReg (result->aop, 1, right->aop->aopu.aop_reg[0]->rIdx) && !aopInReg (result->aop, 2, right->aop->aopu.aop_reg[0]->rIdx) && !aopInReg (result->aop, 3, right->aop->aopu.aop_reg[0]->rIdx)))
13324 countreg = right->aop->aopu.aop_reg[0]->rIdx;
13325 else if (!IS_SM83 && isRegDead (B_IDX, ic) && (sameRegs (left->aop, result->aop) || left->aop->type != AOP_REG || shift_by_lit) &&
13326 !aopInReg (result->aop, 0, B_IDX) && !aopInReg (result->aop, 1, B_IDX) && !aopInReg (result->aop, 2, B_IDX) && !aopInReg (result->aop, 3, B_IDX))
13327 countreg = B_IDX;
13328 else if (isRegDead (A_IDX, ic) && result->aop->regs[A_IDX] < 0 && left->aop->regs[A_IDX] < 0)
13329 countreg = A_IDX;
13330 else if (isRegDead (B_IDX, ic) && result->aop->regs[B_IDX] < 0 && left->aop->regs[B_IDX] < 0)
13331 countreg = B_IDX;
13332 else if (isRegDead (C_IDX, ic) && result->aop->regs[C_IDX] < 0 && left->aop->regs[C_IDX] < 0)
13333 countreg = C_IDX;
13334 else if (IS_Z80N && z80n_de && aopInReg (right->aop, 0, B_IDX))
13335 countreg = B_IDX;
13336 else
13338 UNIMPLEMENTED;
13339 countreg = A_IDX;
13342 if (IS_Z80N && z80n_de && (aopInReg (right->aop, 0, B_IDX) || countreg == B_IDX))
13344 shiftop = result->aop->size == 2 ? ASMOP_DE : ASMOP_E;
13345 cheapMove (ASMOP_B, 0, right->aop, 0, isRegDead (A_IDX, ic));
13346 genMove (shiftop, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, true);
13347 emit2 ("bsla de, b");
13348 cost (2, 8);
13349 goto end;
13352 save_a_outer = (!isRegDead (A_IDX, ic) && countreg == A_IDX && !(shift_by_lit && shiftcount == 1));
13354 if(save_a_outer)
13355 _push (PAIR_AF);
13357 if (!shift_by_lit)
13358 cheapMove (asmopregs[countreg], 0, right->aop, 0, true);
13360 bool save_a_inner = (countreg == A_IDX && !shift_by_lit) &&
13361 !(left->aop->type == AOP_REG && result->aop->type != AOP_REG ||
13362 !IS_SM83 && (left->aop->type == AOP_STK && canAssignToPtr3 (result->aop) || result->aop->type == AOP_STK && canAssignToPtr3 (left->aop)));
13364 shiftop = result->aop;
13365 if (result->aop->type != AOP_REG && left->aop->type == AOP_REG && result->aop->size == left->aop->size && left->aop->regs[countreg] < 0)
13367 bool left_dead = true;
13368 for (int i = 0; i < left->aop->size; i++)
13369 left_dead &= isRegDead (left->aop->aopu.aop_reg[i]->rIdx, ic);
13370 if (left_dead)
13371 shiftop = left->aop;
13374 /* now move the left to the result if they are not the
13375 same */
13376 if (!sameRegs (shiftop, left->aop) || shiftop->type == AOP_REG)
13378 if (save_a_inner)
13379 _push (PAIR_AF);
13381 if (shift_by_lit)
13383 byteshift = shiftcount / 8;
13384 shiftcount %= 8;
13386 size = shiftop->size - byteshift;
13387 int lsize = left->aop->size - byteshift;
13389 bool hl_dead = isPairDead (PAIR_HL, ic) && (countreg != L_IDX && countreg != H_IDX || shift_by_lit);
13390 bool de_dead = isPairDead (PAIR_DE, ic) && (countreg != E_IDX && countreg != D_IDX || shift_by_lit);
13391 genMove_o (shiftop, byteshift, left->aop, 0, size <= lsize ? size : lsize, (save_a_inner || countreg != A_IDX) && (isRegDead (A_IDX, ic) || save_a_outer), hl_dead, de_dead, true, true);
13392 hl_dead &= shiftop->regs[L_IDX] < byteshift && shiftop->regs[L_IDX] < byteshift;
13393 de_dead &= shiftop->regs[E_IDX] < byteshift && shiftop->regs[D_IDX] < byteshift;
13394 genMove_o (shiftop, 0, ASMOP_ZERO, 0, byteshift, (save_a_inner || countreg != A_IDX) && (isRegDead (A_IDX, ic) || save_a_outer), hl_dead, de_dead, true, true);
13396 if (save_a_inner)
13397 _pop (PAIR_AF);
13399 shiftop->valinfo.anything = true;
13401 if (!regalloc_dry_run)
13403 tlbl = newiTempLabel (NULL);
13404 tlbl1 = newiTempLabel (NULL);
13406 size = shiftop->size - byteshift;
13407 offset = byteshift;
13409 if (shift_by_lit && !shiftcount)
13410 goto end;
13411 if (shift_by_lit && shiftcount > 1)
13413 emit2 ("ld %s, !immedbyte", countreg == A_IDX ? "a" : regsZ80[countreg].name, (unsigned)shiftcount);
13414 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13416 else if (!shift_by_lit && !aopIsNotLitVal (right->aop, 0, 1, 0))
13418 emit2 ("inc %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
13419 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
13420 if (!regalloc_dry_run)
13421 emit2 ("jp !tlabel", labelKey2num (tlbl1->key));
13422 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
13424 if (!(shift_by_lit && shiftcount == 1) && !regalloc_dry_run)
13426 emitLabel (tlbl);
13427 if (requiresHL (shiftop))
13428 spillPair (PAIR_HL);
13431 started = false;
13432 regalloc_dry_run_state_scale = shift_by_lit ? shiftcount : 2;
13433 while (size)
13435 if (size >= 2 && offset + 1 >= byteshift &&
13436 shiftop->type == AOP_REG &&
13437 (!started || !IS_SM83) && // sm83 doesn't have wide adc
13438 (getPartPairId (shiftop, offset) == PAIR_HL ||
13439 !started && getPartPairId (shiftop, offset) == PAIR_IY ||
13440 (IS_RAB || optimize.codeSize && !started && !IS_SM83) && getPartPairId (shiftop, offset) == PAIR_DE))
13442 if (shiftop->aopu.aop_reg[offset]->rIdx == L_IDX)
13443 emit3w (started ? A_ADC : A_ADD, ASMOP_HL, ASMOP_HL);
13444 else if (shiftop->aopu.aop_reg[offset]->rIdx == IYL_IDX)
13445 emit3w (A_ADD, ASMOP_IY, ASMOP_IY);
13446 else if (IS_RAB)
13448 if (!started)
13449 emit3 (A_CP, ASMOP_A, ASMOP_A);
13450 emit2 ("rl de");
13451 cost (1, 2);
13453 else
13455 wassert (!IS_SM83);
13456 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
13457 emit3w (started ? A_ADC : A_ADD, ASMOP_HL, ASMOP_HL);
13458 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
13461 started = true;
13462 size -= 2, offset += 2;
13464 else
13466 if (offset >= byteshift)
13468 if (aopInReg (shiftop, offset, A_IDX))
13469 emit3 (started ? A_ADC : A_ADD, ASMOP_A, ASMOP_A);
13470 else
13471 emit3_o (started ? A_RL : A_SLA, shiftop, offset, 0, 0);
13472 started = true;
13474 size--, offset++;
13478 if (!(shift_by_lit && shiftcount == 1))
13480 if (!regalloc_dry_run)
13481 emitLabel (tlbl1);
13482 if (!IS_SM83 && countreg == B_IDX)
13484 if (!regalloc_dry_run)
13485 emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
13486 cost2 (2, 13, 9, 5, 0, 10, 4, 2); // Assume jump taken.
13488 else
13490 emit2 ("dec %s", regsZ80[countreg].name);
13491 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
13492 if (!regalloc_dry_run)
13493 emit2 ("jr NZ,!tlabel", labelKey2num (tlbl->key));
13494 cost2 (2, 12, 8, 5, 12, 8, 3, 3); // Assume jump taken, and optimized to jr.
13498 end:
13499 regalloc_dry_run_state_scale = 1.0f;
13501 if (!shift_by_lit && requiresHL (shiftop)) // Shift by 0 skips over hl adjustments.
13502 spillPair (PAIR_HL);
13504 sym_link *resulttype = operandType (IC_RESULT (ic));
13505 unsigned topbytemask = (IS_BITINT (resulttype) && SPEC_USIGN (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
13506 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
13507 bool maskedtopbyte = (topbytemask != 0xff);
13508 if (maskedtopbyte)
13510 bool pushed_a = false;
13511 if (!isRegDead (A_IDX, ic) || shiftop->regs[A_IDX] >= 0 && shiftop->regs[A_IDX] != result->aop->size - 1)
13513 _push (PAIR_AF);
13514 pushed_a = true;
13516 cheapMove (ASMOP_A, 0, shiftop, result->aop->size - 1, true);
13517 emit2 ("and a, #0x%02x", topbytemask);
13518 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13519 cheapMove (shiftop, result->aop->size - 1, ASMOP_A, 0, true);
13520 if (pushed_a)
13521 _pop (PAIR_AF);
13524 genMove_o (result->aop, 0, shiftop, 0, result->aop->size, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
13526 if (save_a_outer)
13527 _pop (PAIR_AF);
13529 freeAsmop (left, NULL);
13530 freeAsmop (right, NULL);
13531 freeAsmop (result, NULL);
13534 /*-----------------------------------------------------------------*/
13535 /* AccRsh - right shift accumulator by known count */
13536 /*-----------------------------------------------------------------*/
13537 static void
13538 AccRsh (int shCount)
13540 if (shCount >= 2)
13542 /* rotate right accumulator */
13543 AccRol (8 - shCount);
13544 /* and kill the higher order bits */
13545 if (!regalloc_dry_run)
13546 emit2 ("and a, !immedbyte", 0xffu >> shCount);
13547 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13549 else if(shCount)
13550 emit3 (A_SRL, ASMOP_A, 0);
13553 /*-----------------------------------------------------------------*/
13554 /* genrshOne - right shift one byte by known amount */
13555 /*-----------------------------------------------------------------*/
13556 static void
13557 genrshOne (operand *result, operand *left, int shCount, int is_signed, const iCode *ic)
13559 /* Errk */
13560 int size = result->aop->size;
13562 wassert (size == 1);
13564 bool a_dead = isRegDead (A_IDX, ic);
13566 if ((IS_Z180 || IS_EZ80_Z80 || IS_Z80N) && !is_signed && shCount >= 3 && shCount <= 6 + a_dead && // Try to use mlt.
13567 (!IS_Z80N && aopInReg (result->aop, 0, B_IDX) && isPairDead(PAIR_BC, ic) || aopInReg (result->aop, 0, D_IDX) && isPairDead(PAIR_DE, ic) || !IS_Z80N && aopInReg (result->aop, 0, H_IDX) && isPairDead(PAIR_HL, ic)))
13569 PAIR_ID pair = aopInReg (result->aop, 0, B_IDX) ? PAIR_BC : (aopInReg (result->aop, 0, D_IDX) ? PAIR_DE : PAIR_HL);
13570 bool top = aopInReg (left->aop, 0, _pairs[pair].h_idx);
13571 if (!top)
13572 cheapMove (pair == PAIR_BC ? ASMOP_C : (pair == PAIR_DE ? ASMOP_E : ASMOP_L), 0, left->aop, 0, a_dead);
13574 emit2 ("ld %s, !immed%d", top ? _pairs[pair].l : _pairs[pair].h, 1 << (8 - shCount));
13575 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13576 emit2 ("mlt %s", _pairs[pair].name);
13577 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
13579 else if (!IS_SM83 && !IS_RAB && !is_signed && aopSame (result->aop, 0, left->aop, 0, 1) && shCount == 4 && isPairDead (PAIR_HL, ic) && isRegDead (A_IDX, ic) &&
13580 (result->aop->type == AOP_DIR || result->aop->type == AOP_HL || result->aop->type == AOP_IY))
13582 emit3 (A_XOR, ASMOP_A, ASMOP_A);
13583 pointPairToAop (PAIR_HL, result->aop, 0);
13584 emit3 (A_RRD, 0, 0);
13586 else if (!is_signed && // Shifting in the accumulator is cheap for unsigned operands.
13587 (aopInReg (result->aop, 0, A_IDX) ||
13588 result->aop->type != AOP_REG ||
13589 (shCount >= 4 + 2 * a_dead || shCount >= 2 * a_dead && aopInReg (left->aop, 0, A_IDX))))
13591 if (!a_dead)
13592 _push (PAIR_AF);
13593 cheapMove (ASMOP_A, 0, left->aop, 0, true);
13594 AccRsh (shCount);
13595 cheapMove (result->aop, 0, ASMOP_A, 0, true);
13596 if (!a_dead)
13597 _pop (PAIR_AF);
13599 else if (result->aop->type == AOP_REG) // Can shift in destination for register result.
13601 cheapMove (result->aop, 0, left->aop, 0, a_dead);
13603 while (shCount--)
13604 emit3 (is_signed ? A_SRA : A_SRL, result->aop, 0);
13606 else
13608 if (!a_dead)
13609 _push (PAIR_AF);
13610 cheapMove (ASMOP_A, 0, left->aop, 0, true);
13611 while (shCount--)
13612 emit3 (is_signed ? A_SRA : A_SRL, ASMOP_A, 0);
13613 cheapMove (result->aop, 0, ASMOP_A, 0, true);
13614 if (!a_dead)
13615 _pop (PAIR_AF);
13619 /*-----------------------------------------------------------------*/
13620 /* shiftR1Left2Result - shift right one byte from left to result */
13621 /*-----------------------------------------------------------------*/
13622 static void
13623 shiftR1Left2Result (operand *left, int offl, operand *result, int offr, int shCount, int sign)
13625 cheapMove (ASMOP_A, 0, left->aop, offl, true);
13626 if (sign)
13628 while (shCount--)
13629 emit3 (sign ? A_SRA : A_SRL, ASMOP_A, 0);
13631 else
13632 AccRsh (shCount);
13633 cheapMove (result->aop, offr, ASMOP_A, 0, true);
13636 /*-----------------------------------------------------------------*/
13637 /* genrshTwo - right shift two bytes by known amount */
13638 /*-----------------------------------------------------------------*/
13639 static void
13640 genrshTwo (const iCode *ic, operand *result, operand *left, int shCount, int sign)
13642 if (IS_Z80N &&
13643 aopInReg (result->aop, 0, DE_IDX) && isRegDead (B_IDX, ic) &&
13644 shCount != 8)
13646 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, true);
13647 emit2 ("ld b, !immedbyte", (unsigned)shCount);
13648 emit2 (sign ? "bsra de, b" : "bsrl de, b");
13649 cost (4, 15);
13651 else if (shCount >= 8)
13653 shCount -= 8;
13654 if (shCount)
13655 shiftR1Left2Result (left, MSB16, result, LSB, shCount, sign);
13656 else
13657 cheapMove (result->aop, 0, left->aop, 1, isRegDead (A_IDX, ic));
13658 if (sign)
13660 /* Sign extend the result */
13661 if (result->aop->type != AOP_REG && left->aop->type == AOP_REG)
13662 cheapMove (ASMOP_A, 0, left->aop, 1, true);
13663 else
13664 cheapMove (ASMOP_A, 0, result->aop, 0, true);
13665 emit3 (A_RLCA, 0, 0);
13666 emit3 (A_SBC, ASMOP_A, ASMOP_A);
13667 cheapMove (result->aop, 1, ASMOP_A, 0, true);
13669 else
13670 cheapMove (result->aop, 1, ASMOP_ZERO, 0, true);
13672 else
13673 shiftR2Left2Result (ic, left, LSB, result, LSB, shCount, sign);
13676 /*-----------------------------------------------------------------*/
13677 /* genRightShiftLiteral - right shifting by known count */
13678 /*-----------------------------------------------------------------*/
13679 static void
13680 genRightShiftLiteral (operand *left, operand *right, operand *result, const iCode *ic, int sign)
13682 unsigned int shCount = (unsigned int) ulFromVal (right->aop->aopu.aop_lit);
13683 unsigned int size;
13685 freeAsmop (right, NULL);
13687 aopOp (left, ic, false, false);
13688 aopOp (result, ic, true, false);
13690 size = getSize (operandType (result));
13692 /* I suppose that the left size >= result size */
13693 wassert (getSize (operandType (left)) >= size);
13695 if (shCount >= (size * 8))
13697 if (!SPEC_USIGN (getSpec (operandType (left))))
13699 cheapMove (ASMOP_A, 0, left->aop, 0, true);
13700 emit3 (A_RLCA, 0, 0);
13701 emit3 (A_SBC, ASMOP_A, ASMOP_A);
13702 while (size--)
13703 cheapMove (result->aop, size, ASMOP_A, 0, true);
13705 else
13706 genMove (result->aop, ASMOP_ZERO, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), false, true);
13708 else
13710 switch (size)
13712 case 1:
13713 genrshOne (result, left, shCount, sign, ic);
13714 break;
13715 case 2:
13716 genrshTwo (ic, result, left, shCount, sign);
13717 break;
13718 case 4:
13719 wassertl (0, "Asked to shift right a long which should be handled in generic right shift function.");
13720 break;
13721 default:
13722 wassertl (0, "Entered default case in right shift delegate");
13725 freeAsmop (left, NULL);
13726 freeAsmop (result, NULL);
13729 /*-----------------------------------------------------------------*/
13730 /* genRightShift - generate code for right shifting */
13731 /*-----------------------------------------------------------------*/
13732 static void
13733 genRightShift (const iCode * ic)
13735 operand *right, *left, *result;
13736 asmop *shiftop;
13737 int size, offset, first = 1;
13738 bool is_signed;
13739 int countreg;
13740 bool shift_by_lit, shift_by_one, shift_by_zero;
13741 int shiftcount = 0;
13742 int byteoffset = 0;
13743 bool save_a;
13745 symbol *tlbl = 0, *tlbl1 = 0;
13747 right = IC_RIGHT (ic);
13748 left = IC_LEFT (ic);
13749 result = IC_RESULT (ic);
13751 /* if signed then we do it the hard way preserve the
13752 sign bit moving it inwards */
13753 is_signed = !SPEC_USIGN (getSpec (operandType (left)));
13755 aopOp (right, ic, FALSE, FALSE);
13757 /* if the shift count is known then do it
13758 as efficiently as possible */
13759 if (right->aop->type == AOP_LIT && getSize (operandType (result)) <= 2)
13761 genRightShiftLiteral (left, right, result, ic, is_signed);
13762 freeAsmop (right, NULL);
13763 return;
13766 /* Useful for the case of shifting a size > 2 value by a literal */
13767 shift_by_lit = right->aop->type == AOP_LIT;
13768 if (shift_by_lit)
13769 shiftcount = ulFromVal (right->aop->aopu.aop_lit);
13771 aopOp (result, ic, true, false);
13772 aopOp (left, ic, false, false);
13774 if (right->aop->type == AOP_REG && !bitVectBitValue (ic->rSurv, right->aop->aopu.aop_reg[0]->rIdx) && right->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && (sameRegs (left->aop, result->aop) || left->aop->type != AOP_REG) &&
13775 (result->aop->type != AOP_REG ||
13776 result->aop->aopu.aop_reg[0]->rIdx != right->aop->aopu.aop_reg[0]->rIdx &&
13777 (result->aop->size < 2 || result->aop->aopu.aop_reg[1]->rIdx != right->aop->aopu.aop_reg[0]->rIdx &&
13778 (result->aop->size < 3 || result->aop->aopu.aop_reg[2]->rIdx != right->aop->aopu.aop_reg[0]->rIdx &&
13779 (result->aop->size < 4 || result->aop->aopu.aop_reg[3]->rIdx != right->aop->aopu.aop_reg[0]->rIdx)))))
13780 countreg = right->aop->aopu.aop_reg[0]->rIdx;
13781 else if (!IS_SM83 && isRegDead (B_IDX, ic) && (sameRegs (left->aop, result->aop) || left->aop->type != AOP_REG || shift_by_lit) &&
13782 (result->aop->type != AOP_REG ||
13783 result->aop->aopu.aop_reg[0]->rIdx != B_IDX &&
13784 (result->aop->size < 2 || result->aop->aopu.aop_reg[1]->rIdx != B_IDX &&
13785 (result->aop->size < 3 || result->aop->aopu.aop_reg[2]->rIdx != B_IDX &&
13786 (result->aop->size < 4 || result->aop->aopu.aop_reg[3]->rIdx != B_IDX)))))
13787 countreg = B_IDX;
13788 else
13789 countreg = A_IDX;
13791 if (IS_Z80N && isRegDead (PAIR_DE, ic) &&
13792 (result->aop->size == 2 && (aopInReg (result->aop, 0, DE_IDX) || aopInReg (left->aop, 0, DE_IDX)) ||
13793 result->aop->size == 1 && (aopInReg (result->aop, 0, D_IDX) || aopInReg (left->aop, 0, D_IDX))) &&
13794 (aopInReg (right->aop, 0, B_IDX) || countreg == B_IDX))
13796 shiftop = result->aop->size == 2 ? ASMOP_DE : ASMOP_D;
13797 cheapMove (ASMOP_B, 0, right->aop, 0, isRegDead (A_IDX, ic));
13798 genMove (shiftop, left->aop, isRegDead (A_IDX, ic), isRegDead (HL_IDX, ic), true, true);
13799 emit2 (is_signed ? "bsra de, b" : "bsrl de, b");
13800 cost (2, 8);
13801 goto end;
13804 if (!shift_by_lit)
13805 cheapMove (countreg == A_IDX ? ASMOP_A : asmopregs[countreg], 0, right->aop, 0, true);
13807 save_a = (countreg == A_IDX && !shift_by_lit) &&
13808 !(left->aop->type == AOP_REG && result->aop->type != AOP_REG ||
13809 !IS_SM83 && (left->aop->type == AOP_STK && canAssignToPtr3 (result->aop) || result->aop->type == AOP_STK && canAssignToPtr3 (left->aop)));
13811 shiftop = result->aop;
13812 if (result->aop->type != AOP_REG && left->aop->type == AOP_REG && result->aop->size == left->aop->size && left->aop->regs[countreg] < 0)
13814 bool left_dead = true;
13815 for (int i = 0; i < left->aop->size; i++)
13816 left_dead &= isRegDead (left->aop->aopu.aop_reg[i]->rIdx, ic);
13817 if (left_dead)
13818 shiftop = left->aop;
13821 /* now move the left to the shiftop if they are not the
13822 same */
13823 if (!sameRegs (shiftop, left->aop) || shiftop->type == AOP_REG)
13825 int soffset = 0;
13826 size = shiftop->size;
13828 if (!is_signed && shift_by_lit)
13830 byteoffset = shiftcount / 8;
13831 shiftcount %= 8;
13832 soffset = byteoffset;
13833 size -= byteoffset;
13836 if (save_a)
13837 _push (PAIR_AF);
13839 bool hl_dead = isPairDead (PAIR_HL, ic) && (countreg != L_IDX && countreg != H_IDX || shift_by_lit);
13840 genMove_o (shiftop, 0, left->aop, soffset, size, true, hl_dead, false, true, true);
13841 hl_dead &= (shiftop->regs[L_IDX] < 0 || shiftop->regs[L_IDX] >= size) && (shiftop->regs[H_IDX] < 0 || shiftop->regs[H_IDX] >= size);
13842 genMove_o (shiftop, shiftop->size - byteoffset, ASMOP_ZERO, 0, byteoffset, true, hl_dead, false, true, true);
13844 if (save_a)
13845 _pop (PAIR_AF);
13847 shiftop->valinfo.anything = true;
13849 shift_by_one = (shift_by_lit && shiftcount == 1);
13850 shift_by_zero = (shift_by_lit && shiftcount == 0);
13852 if (!regalloc_dry_run)
13854 tlbl = newiTempLabel (NULL);
13855 tlbl1 = newiTempLabel (NULL);
13857 size = result->aop->size;
13858 offset = size - 1;
13860 if (shift_by_zero)
13861 goto end;
13862 else if (shift_by_lit && shiftcount > 1)
13864 emit2 ("ld %s, !immedbyte", countreg == A_IDX ? "a" : regsZ80[countreg].name, (unsigned)shiftcount);
13865 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13867 else if (!shift_by_lit && !aopIsNotLitVal (right->aop, 0, 1, 0))
13869 emit2 ("inc %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
13870 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
13871 if (!regalloc_dry_run)
13872 emit2 ("jp !tlabel", labelKey2num (tlbl1->key));
13873 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
13875 if (!shift_by_one && !regalloc_dry_run)
13876 IS_SM83 ? emitLabelSpill (tlbl) : emitLabel (tlbl);
13878 if (!shift_by_one && requiresHL (shiftop))
13879 spillPair (PAIR_HL);
13881 regalloc_dry_run_state_scale = shift_by_lit ? shiftcount : 2;
13882 while (size)
13884 if (IS_RAB && !(is_signed && first) && size >= 2 && byteoffset < 2 && shiftop->type == AOP_REG &&
13885 (getPartPairId (shiftop, offset - 1) == PAIR_HL || getPartPairId (shiftop, offset - 1) == PAIR_DE))
13887 if (first)
13889 emit3 (A_CP, ASMOP_A, ASMOP_A);
13890 first = 0;
13892 emit2 (shiftop->aopu.aop_reg[offset - 1]->rIdx == L_IDX ? "rr hl" : "rr de");
13893 cost (1, 2);
13894 size -= 2, offset -= 2;
13896 else if (!is_signed && first && byteoffset--) // Skip known 0 bytes
13897 size--, offset--;
13898 else if (first)
13900 emit3_o (is_signed ? A_SRA : A_SRL, shiftop, offset, 0, 0);
13901 first = 0;
13902 size--, offset--;
13904 else
13906 emit3_o (A_RR, shiftop, offset, 0, 0);
13907 size--, offset--;
13911 if (!shift_by_one)
13913 if (!regalloc_dry_run)
13914 emitLabel (tlbl1);
13915 if (!IS_SM83 && countreg == B_IDX)
13917 if (!regalloc_dry_run)
13918 emit2 ("djnz !tlabel", labelKey2num (tlbl->key));
13919 cost2 (2, 13, 9, 5, 0, 10, 4, 2); // Assume jump taken.
13921 else
13923 emit2 ("dec %s", countreg == A_IDX ? "a" : regsZ80[countreg].name);
13924 cost2 (1, 4, 4, 2, 4, 2, 1, 1);
13925 if (!regalloc_dry_run)
13926 emit2 ("jr NZ, !tlabel", labelKey2num (tlbl->key));
13927 cost2 (2, 12, 8, 5, 12, 8, 3, 3); // Assume jump taken, and optimized to jr.
13931 end:
13932 regalloc_dry_run_state_scale = 1.0f;
13933 if (!shift_by_lit && requiresHL (shiftop)) // Shift by 0 skips over hl adjustments.
13934 spillPair (PAIR_HL);
13936 genMove_o (result->aop, 0, shiftop, 0, result->aop->size, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true, true);
13938 freeAsmop (left, NULL);
13939 freeAsmop (right, NULL);
13940 freeAsmop (result, NULL);
13943 /*-----------------------------------------------------------------*/
13944 /* unpackMaskA - generate masking code for unpacking last byte */
13945 /* of bitfield. And mask for unsigned, sign extension for signed. */
13946 /*-----------------------------------------------------------------*/
13947 static void
13948 unpackMaskA(sym_link *type, int len)
13950 if (SPEC_USIGN (type) || len != 1)
13952 emit2 ("and a, !immedbyte", ((unsigned)-1 & 0xffu) >> (8 - len));
13953 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
13955 if (!SPEC_USIGN (type))
13957 if (len == 1)
13959 emit3(A_RRA, 0, 0);
13960 emit3(A_SBC, ASMOP_A, ASMOP_A);
13962 else
13964 emit2 ("bit %d, a", len - 1);
13965 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
13966 if (!regalloc_dry_run)
13968 symbol *tlbl = newiTempLabel (NULL);
13969 emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
13970 emit2 ("or a, !immedbyte", ((0xffu << len) & 0xffu));
13971 emitLabel (tlbl);
13973 cost2 (4, 12, 8, 5, 12, 8, 3, 3); // Assume nonnegative, jp optimzed to jr.
13978 /*-----------------------------------------------------------------*/
13979 /* genUnpackBits - generates code for unpacking bits */
13980 /*-----------------------------------------------------------------*/
13981 static void
13982 genUnpackBits (operand *result, int pair, const iCode *ic)
13984 int offset = 0; /* result byte offset */
13985 int rsize; /* result size */
13986 int rlen = 0; /* remaining bit-field length */
13987 sym_link *etype; /* bit-field type information */
13988 unsigned blen; /* bit-field length */
13989 unsigned bstr; /* bit-field starting bit within byte */
13990 unsigned int pairincrement = 0;
13992 emitDebug ("; genUnpackBits");
13994 etype = getSpec (operandType (result));
13995 rsize = getSize (operandType (result));
13996 blen = SPEC_BLEN (etype);
13997 bstr = SPEC_BSTR (etype);
13999 /* If the bit-field length is less than a byte */
14000 if (blen < 8)
14002 emit2 ("ld a, !mems", _pairs[pair].name);
14003 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
14004 AccRol (8 - bstr);
14005 unpackMaskA (etype, blen);
14006 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14007 goto finish;
14010 /* TODO: what if pair == PAIR_DE ? */
14011 if (getPairId (result->aop) == PAIR_HL ||
14012 result->aop->type == AOP_REG && rsize == 2 && (result->aop->aopu.aop_reg[0]->rIdx == L_IDX
14013 || result->aop->aopu.aop_reg[0]->rIdx == H_IDX))
14015 emit2 ("!ldahli");
14016 regalloc_dry_run_cost++;
14017 if (result->aop->type != AOP_REG || result->aop->aopu.aop_reg[0]->rIdx != H_IDX)
14019 emit2 ("ld h, !*hl");
14020 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
14021 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14022 emit3 (A_LD, ASMOP_A, ASMOP_H);
14024 else
14026 emit2 ("ld l, !*hl");
14027 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
14028 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14029 emit3 (A_LD, ASMOP_A, ASMOP_L);
14031 unpackMaskA (etype, blen - 8);
14032 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14033 spillPair (PAIR_HL);
14034 return;
14037 /* Bit field did not fit in a byte. Copy all
14038 but the partial byte at the end. */
14039 for (rlen = blen; rlen >= 8; rlen -= 8)
14041 emit2 ("ld a, !mems", _pairs[pair].name);
14042 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14043 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14044 if (rlen > 8)
14046 emit2 ("inc %s", _pairs[pair].name);
14047 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14048 _G.pairs[pair].offset++;
14049 pairincrement++;
14053 /* Handle the partial byte at the end */
14054 if (rlen)
14056 emit2 ("ld a, !mems", _pairs[pair].name);
14057 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14058 unpackMaskA (etype, rlen);
14059 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14062 finish:
14063 if (!isPairDead (pair, ic))
14064 while (pairincrement)
14066 emit2 ("dec %s", _pairs[pair].name);
14067 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14068 pairincrement--;
14069 _G.pairs[pair].offset--;
14072 if (offset < rsize)
14074 asmop *source;
14076 if (SPEC_USIGN (etype))
14077 source = ASMOP_ZERO;
14078 else
14080 /* signed bit-field: sign extension with 0x00 or 0xff */
14081 emit3 (A_RLA, 0, 0);
14082 emit3 (A_SBC, ASMOP_A, ASMOP_A);
14083 source = ASMOP_A;
14085 rsize -= offset;
14086 while (rsize--)
14087 cheapMove (result->aop, offset++, source, 0, true);
14091 static void
14092 _moveFrom_tpair_ (asmop * aop, int offset, PAIR_ID pair)
14094 emitDebug ("; _moveFrom_tpair_()");
14095 if (pair == PAIR_HL && aop->type == AOP_REG)
14097 if (!regalloc_dry_run)
14098 aopPut (aop, "!*hl", offset);
14099 ld_cost (aop, 0, aopInReg (aop, 0, A_IDX) ? ASMOP_L : ASMOP_A, 0, true);
14101 else
14103 emit2 ("ld a, !mems", _pairs[pair].name);
14104 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14105 cheapMove (aop, offset, ASMOP_A, 0, true);
14109 static void offsetPair (PAIR_ID pair, PAIR_ID extrapair, bool save_extrapair, int val)
14111 if (abs (val) < (save_extrapair ? 6 : 4) || pair != PAIR_HL && pair != PAIR_IY && pair != PAIR_IX)
14113 while (val)
14115 emit2 (val > 0 ? "inc %s" : "dec %s", _pairs[pair].name);
14116 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14117 if (val > 0)
14118 val--;
14119 else
14120 val++;
14123 else
14125 if (save_extrapair)
14126 _push (extrapair);
14127 emit2 ("ld %s, !immedword", _pairs[extrapair].name, (unsigned)val);
14128 if (extrapair == PAIR_IY)
14129 cost2 (4 - IS_TLCS90, 14, 12, 8, 0, 6, 4, 4);
14130 else
14131 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14132 emit2 ("add %s, %s", _pairs[pair].name, _pairs[extrapair].name);
14133 if (pair == PAIR_HL)
14134 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
14135 else
14136 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
14137 if (save_extrapair)
14138 _pop (extrapair);
14142 /*------------------------------------------------------------------*/
14143 /* init_stackop - initialize asmop for stack location */
14144 /*------------------------------------------------------------------*/
14145 static void
14146 init_stackop (asmop *stackop, int size, long int stk_off)
14148 stackop->size = size;
14149 memset (stackop->regs, -1, 9);
14150 stackop->aopu.aop_stk = stk_off;
14152 if (!IS_SM83 && (_G.omitFramePtr || stk_off < INT8MIN || stk_off > (int) (INT8MAX - size)))
14153 stackop->type = AOP_EXSTK;
14154 else
14155 stackop->type = AOP_STK;
14157 stackop->valinfo.anything = true;
14160 /*-----------------------------------------------------------------*/
14161 /* genPointerGet - generate code for pointer get */
14162 /*-----------------------------------------------------------------*/
14163 static void
14164 genPointerGet (const iCode *ic)
14166 operand *left, *right, *result;
14167 int size, offset, rightval;
14168 int pair = PAIR_HL, extrapair;
14169 bool pushed_pair = FALSE;
14170 bool pushed_a = FALSE;
14171 bool surviving_a = !isRegDead (A_IDX, ic);
14172 bool rightval_in_range;
14174 left = IC_LEFT (ic);
14175 right = IC_RIGHT (ic);
14176 result = IC_RESULT (ic);
14177 bool bit_field = IS_BITVAR (operandType (result)); // Should be IS_BITVAR (operandType (left)->next), but conflicts with optimizations that reuses pointers (when reading from a union of a struct containing bit-fields and other types).
14179 aopOp (left, ic, false, false);
14180 aopOp (result, ic, true, false);
14181 size = result->aop->size;
14183 /* Historically GET_VALUE_AT_ADDRESS didn't have a right operand */
14184 wassertl (right, "GET_VALUE_AT_ADDRESS without right operand");
14185 wassertl (IS_OP_LITERAL (IC_RIGHT (ic)), "GET_VALUE_AT_ADDRESS with non-literal right operand");
14186 rightval = (int)operandLitValue (right);
14187 rightval_in_range = (rightval >= -128 && rightval + size - 1 < 127);
14189 if (IS_SM83 && left->aop->type == AOP_STK) // Try to avoid (hl) to hl copy, which requires 3 instructions and free a.
14190 pair = PAIR_DE;
14191 if ((IS_SM83 || IY_RESERVED) && requiresHL (result->aop) && size > 1 && result->aop->type != AOP_REG)
14192 pair = PAIR_DE;
14194 if (IS_SM83 && size == 1 && left->aop->type == AOP_LIT && (((unsigned long)(operandLitValue (left) + rightval) & 0xff00) == 0xff00) && isRegDead (A_IDX, ic) && !bit_field) // SM83 has special instructions for address range 0xff00 - 0xffff.
14196 emit2 ("ldh a, !mems", aopGetLitWordLong (left->aop, rightval, true));
14197 cost (2, 12);
14198 cheapMove (result->aop, 0, ASMOP_A, 0, true);
14199 goto release;
14201 if ((left->aop->type == AOP_IMMD || left->aop->type == AOP_LIT && !rightval) && size == 1 && aopInReg (result->aop, 0, A_IDX) && !bit_field)
14203 emit2 ("ld a, !mems", aopGetLitWordLong (left->aop, rightval, true));
14204 cost2 (3, 13, 12, 9, 16, 10, 4, 4);
14205 goto release;
14207 else if (!IS_SM83 && (left->aop->type == AOP_IMMD || left->aop->type == AOP_LIT && !rightval) && isPair (result->aop) && !bit_field)
14209 PAIR_ID pair = getPairId (result->aop);
14210 emit2 ("ld %s, !mems", _pairs[pair].name, aopGetLitWordLong (left->aop, rightval, TRUE));
14211 if (pair == PAIR_HL)
14212 cost2 (3, 16 , 15, 11, 0, 12, 5, 5);
14213 else
14214 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
14215 goto release;
14217 else if (!IS_SM83 && (left->aop->type == AOP_IMMD) && getPartPairId (result->aop, 0) != PAIR_INVALID && getPartPairId (result->aop, 2) != PAIR_INVALID)
14219 PAIR_ID pair;
14220 pair = getPartPairId (result->aop, 0);
14221 emit2 ("ld %s, !mems", _pairs[pair].name, aopGetLitWordLong (left->aop, rightval, TRUE));
14222 if (pair == PAIR_HL)
14223 cost2 (3, 16 , 15, 11, 0, 12, 5, 5);
14224 else
14225 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
14226 pair = getPartPairId (result->aop, 2);
14227 emit2 ("ld %s, !mems", _pairs[pair].name, aopGetLitWordLong (left->aop, rightval + 2, TRUE));
14228 if (pair == PAIR_HL)
14229 cost2 (3, 16 , 15, 11, 0, 12, 5, 5);
14230 else
14231 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
14232 goto release;
14234 else if (left->aop->type == AOP_STL && !bit_field && size <= 4)
14236 struct asmop saop;
14237 init_stackop (&saop, size, left->aop->aopu.aop_stk + rightval);
14238 genMove (result->aop, &saop, !surviving_a, isPairDead(PAIR_HL, ic), isPairDead(PAIR_DE, ic), isPairDead(PAIR_IY, ic));
14239 goto release;
14242 if (IS_SM83)
14243 wassert (!rightval);
14245 if (isPair (left->aop) && size == 1 && !bit_field && !rightval)
14247 /* Just do it */
14248 if ((getPairId (left->aop) == PAIR_HL || getPairId (left->aop) == PAIR_IY) && result->aop->type == AOP_REG)
14250 if (!regalloc_dry_run) // Todo: More exact cost.
14252 struct dbuf_s dbuf;
14254 dbuf_init (&dbuf, 128);
14255 dbuf_tprintf (&dbuf, "!mems", getPairName (left->aop));
14256 aopPut (result->aop, dbuf_c_str (&dbuf), 0);
14257 dbuf_destroy (&dbuf);
14259 ld_cost (result->aop, 0, aopInReg(result->aop, 0, A_IDX) ? ASMOP_L : ASMOP_A, 0, true);
14261 else
14263 if (surviving_a && !pushed_a)
14264 _push (PAIR_AF), pushed_a = true;
14265 emit2 ("ld a, !mems", getPairName (left->aop));
14266 if (getPairId (left->aop) == PAIR_IY)
14267 cost2 (3, 19, 14, 9, 0, 10, 4, 5);
14268 else
14269 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14270 genMove (result->aop, ASMOP_A, true, isPairDead(PAIR_HL, ic), isPairDead(PAIR_DE, ic), true);
14273 goto release;
14276 if (getPairId (left->aop) == PAIR_IY && !bit_field && rightval_in_range)
14278 offset = 0;
14280 if (IS_RAB && getPartPairId (result->aop, 0) == PAIR_HL)
14282 emit2 ("ld hl, %d (iy)", rightval);
14283 cost (2, 9);
14284 cost (2, 9);
14285 offset = 2;
14286 size -= 2;
14288 else if ((IS_EZ80_Z80 || IS_TLCS90) && getPartPairId (result->aop, 0) != PAIR_INVALID)
14290 emit2 ("ld %s, %d (iy)", _pairs[getPartPairId (result->aop, 0)].name, rightval);
14291 cost2 (3, 0, 0, 0, 0, 12, 5, 0);
14292 offset = 2;
14293 size -= 2;
14296 if (!size)
14297 goto release;
14299 /* Just do it */
14300 if (surviving_a && !pushed_a)
14301 _push (PAIR_AF), pushed_a = TRUE;
14303 while (size--)
14305 if (!regalloc_dry_run)
14307 struct dbuf_s dbuf;
14309 dbuf_init (&dbuf, 128);
14310 dbuf_tprintf (&dbuf, "!*iyx", rightval + offset);
14311 aopPut (result->aop, dbuf_c_str (&dbuf), offset);
14312 dbuf_destroy (&dbuf);
14314 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // Assume ld r, d(iy)
14315 offset++;
14318 goto release;
14321 // Using ldir is cheapest for large memory-to-memory transfers.
14322 // sm83 doesn't have ldir. Rabbit 2000 to Rabbit 3000 (i.e. r2k and r2ka ports) have a wait-state bug breaking ldir between different types of memory.
14323 if (!IS_SM83 && (!IS_R2K && !IS_R2KA || left->aop->type == AOP_STL) && !bit_field && (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK) && size > 2)
14325 int fp_offset, sp_offset;
14327 if(!isPairDead (PAIR_HL, ic))
14328 _push (PAIR_HL);
14329 if(!isPairDead (PAIR_DE, ic))
14330 _push (PAIR_DE);
14331 if(!isPairDead (PAIR_BC, ic))
14332 _push (PAIR_BC);
14334 fp_offset = result->aop->aopu.aop_stk + (result->aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
14335 sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
14337 if (IS_EZ80_Z80 && !_G.omitFramePtr && fp_offset >= -128 && fp_offset < 128)
14339 if (left->aop->type == AOP_IMMD)
14341 emit2 ("ld hl, %s", aopGetLitWordLong (left->aop, rightval, TRUE));
14342 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14344 else
14345 fetchPair (PAIR_HL, left->aop);
14346 emit2 ("lea de, ix, !immed%d", fp_offset);
14347 cost (3, 3);
14349 else
14351 if (left->aop->type == AOP_IMMD)
14353 emit2 ("ld de, %s", aopGetLitWordLong (left->aop, rightval, TRUE));
14354 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14356 else
14357 genMove (ASMOP_DE, left->aop, isRegDead (A_IDX, ic), true, true, true);
14358 emit2 ("!ldahlsp", sp_offset);
14359 regalloc_dry_run_cost += 4;
14360 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
14363 if (rightval && left->aop->type != AOP_IMMD)
14364 if (abs(rightval) < 4)
14366 for(;rightval > 0; rightval--)
14367 emit3w (A_INC, ASMOP_HL, 0);
14368 for(;rightval < 0; rightval++)
14369 emit3w (A_DEC, ASMOP_HL, 0);
14371 else
14373 emit2 ("ld bc, !immedword", (unsigned)rightval);
14374 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14375 emit3w (A_ADD, ASMOP_HL, ASMOP_BC);
14376 rightval = 0;
14379 emit2 ("ld bc, !immedword", (unsigned)size);
14380 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14381 emit2 ("ldir");
14382 cost2 (2, 21 * size - 5, 14 * size - 2, 7 * size - 1, 0, 18 * size - 4, 2 * size - 1, 4 * size);
14383 spillPair (PAIR_HL);
14384 spillPair (PAIR_DE);
14385 spillPair (PAIR_BC);
14387 if(!isPairDead (PAIR_BC, ic))
14388 _pop (PAIR_BC);
14389 if(!isPairDead (PAIR_DE, ic))
14390 _pop (PAIR_DE);
14391 if(!isPairDead (PAIR_HL, ic))
14392 _pop (PAIR_HL);
14394 goto release;
14397 extrapair = isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
14399 if (!surviving_a && (getPairId (left->aop) == PAIR_BC || getPairId (left->aop) == PAIR_DE) && isPairDead (getPairId (left->aop), ic) && abs(rightval) <= 2 && !bit_field && size < 2) // Use inc ss (size < 2 condition to avoid overwriting pair with result)
14400 pair = getPairId (left->aop);
14402 /* For now we always load into temp pair */
14403 /* if this is rematerializable */
14404 if (!IS_SM83 && (getPairId (left->aop) == PAIR_BC || getPairId (left->aop) == PAIR_DE) && result->aop->type == AOP_STK && !rightval
14405 || getPairId (left->aop) == PAIR_IY && SPEC_BLEN (getSpec (operandType (result))) < 8 && rightval_in_range)
14406 pair = getPairId (left->aop);
14407 else
14409 if (!isPairDead (pair, ic) && size > 1 && (getPairId (left->aop) != pair || rightval || bit_field || size > 2)) // For simple cases, restoring via dec is cheaper than push / pop.
14410 _push (pair), pushed_pair = TRUE;
14411 if (left->aop->type == AOP_IMMD)
14413 emit2 ("ld %s, %s", _pairs[pair].name, aopGetLitWordLong (left->aop, rightval, TRUE));
14414 regalloc_dry_run_cost += 3;
14415 spillPair (pair);
14416 rightval = 0;
14418 else if (pair == PAIR_HL && rightval > 2 && (getPairId (left->aop) == PAIR_BC || getPairId (left->aop) == PAIR_DE)) // Cheaper than moving to hl followed by offset adjustment.
14420 emit2 ("ld hl, !immed%d", rightval);
14421 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14422 emit2 ("add hl, %s", _pairs[getPairId (left->aop)].name);
14423 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
14424 spillPair (pair);
14425 rightval = 0;
14427 else if (pair == PAIR_HL && left->aop->type == AOP_STL)
14429 emit2 ("ld hl, !immed%d", spOffset (left->aop->aopu.aop_stk) + rightval);
14430 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
14431 emit2 ("add hl, sp");
14432 cost2 (1 + IS_TLCS90, 11, 7, 2, 8, 8, 1, 1);
14433 spillPair (pair);
14434 rightval = 0;
14436 else
14437 fetchPair (pair, left->aop);
14440 /* if bit then unpack */
14441 if (bit_field)
14443 offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
14444 genUnpackBits (result, pair, ic);
14445 if (rightval)
14446 spillPair (pair);
14448 goto release;
14451 if (isPair (result->aop) && IS_EZ80_Z80 && getPairId (left->aop) == PAIR_HL && !bit_field && !rightval)
14453 emit2 ("ld %s, !*hl", _pairs[getPairId (result->aop)].name);
14454 cost (2, 4);
14455 goto release;
14457 else if (pair == PAIR_HL && (getPairId (result->aop) == PAIR_HL || size == 2 && (aopInReg (result->aop, 0, L_IDX) || aopInReg (result->aop, 0, H_IDX))))
14459 wassertl (size == 2, "HL must be of size 2");
14460 if (IS_RAB && getPairId (result->aop) == PAIR_HL && rightval_in_range)
14462 emit2 ("ld hl, %d !*hl", rightval);
14463 cost (3, 11);
14465 else if (IS_EZ80_Z80 && getPairId (result->aop) == PAIR_HL && !rightval)
14467 emit2 ("ld hl, !*hl");
14468 cost (2, 4);
14470 else if (aopInReg (result->aop, 1, A_IDX))
14472 offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval + 1);
14473 emit2 ("!ldahld");
14474 if (!regalloc_dry_run)
14475 aopPut (result->aop, "!*hl", 0);
14476 regalloc_dry_run_cost += 3;
14478 else
14480 if (surviving_a && !pushed_a)
14481 _push (PAIR_AF), pushed_a = TRUE;
14482 offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
14483 emit2 ("!ldahli");
14484 if (!regalloc_dry_run)
14485 aopPut (result->aop, "!*hl", 1);
14486 regalloc_dry_run_cost += 3;
14487 cheapMove (result->aop, 0, ASMOP_A, 0, true);
14489 spillPair (PAIR_HL);
14490 goto release;
14493 offsetPair (pair, extrapair, !isPairDead (extrapair, ic), rightval);
14495 if (pair == PAIR_HL
14496 || (!IS_SM83 && (getPairId (left->aop) == PAIR_BC || getPairId (left->aop) == PAIR_DE)
14497 && result->aop->type == AOP_STK))
14499 size = result->aop->size;
14500 offset = 0;
14501 int last_offset = 0;
14503 /* might use ld a,(hl) followed by ld d (iy),a */
14504 if ((result->aop->type == AOP_EXSTK || result->aop->type == AOP_STK) && surviving_a && !pushed_a)
14505 _push (PAIR_AF), pushed_a = TRUE;
14507 if (size >= 2 && pair == PAIR_HL && result->aop->type == AOP_REG)
14509 int i, l = -10, h = -10, r;
14510 for (i = 0; i < size; i++)
14512 if (result->aop->aopu.aop_reg[i]->rIdx == L_IDX)
14513 l = i;
14514 else if (result->aop->aopu.aop_reg[i]->rIdx == H_IDX)
14515 h = i;
14518 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.
14520 r = (l == -10 ? h : l);
14522 while (offset < size)
14524 if (offset != r)
14525 _moveFrom_tpair_ (result->aop, offset, pair);
14527 if (offset < size)
14529 offset++;
14530 emit2 ("inc %s", _pairs[pair].name);
14531 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14532 _G.pairs[pair].offset++;
14536 for (size = offset; size != r; size--)
14538 emit2 ("dec %s", _pairs[pair].name);
14539 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14542 _moveFrom_tpair_ (result->aop, r, pair);
14544 // No fixup since result uses HL.
14545 spillPair (pair);
14546 goto release;
14548 else if (l >= 0 && h >= 0) // Two bytes of result somewehere in hl. Assign them last and use a for caching.
14550 while (offset < size)
14552 last_offset = offset;
14554 if (IS_EZ80_Z80 && offset != l && offset != h && getPairId_o (result->aop, offset) != PAIR_INVALID)
14556 emit2 ("ld %s, !*hl", _pairs[getPairId_o (result->aop, offset)].name);
14557 cost (2, 4);
14558 offset += 2;
14559 if (offset < size)
14561 emit2 ("inc %s", _pairs[pair].name);
14562 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14563 emit2 ("inc %s", _pairs[pair].name);
14564 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14565 _G.pairs[pair].offset += 2;
14567 continue;
14570 if (offset != l && offset != h)
14571 _moveFrom_tpair_ (result->aop, offset, pair);
14572 offset++;
14574 if (offset < size)
14576 emit2 ("inc %s", _pairs[pair].name);
14577 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14578 _G.pairs[pair].offset++;
14582 r = (l > h ? l : h);
14583 for (size = last_offset; size != r; size--)
14585 emit2 ("dec %s", _pairs[pair].name);
14586 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14588 if ((surviving_a || result->aop->regs[A_IDX] >= 0) && !pushed_a)
14589 _push (PAIR_AF), pushed_a = true;
14590 _moveFrom_tpair_ (ASMOP_A, 0, pair);
14592 r = (l < h ? l : h);
14593 for (; size != r; size--)
14595 emit2 ("dec %s", _pairs[pair].name);
14596 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14598 _moveFrom_tpair_ (result->aop, r, pair);
14600 r = (l > h ? l : h);
14601 cheapMove (result->aop, r, ASMOP_A, 0, true);
14603 // No fixup since result uses HL.
14604 spillPair (pair);
14605 goto release;
14609 while (offset < size)
14611 if (result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < offset)
14612 surviving_a = true;
14614 last_offset = offset;
14616 if (IS_EZ80_Z80 && getPairId_o (result->aop, offset) != PAIR_INVALID)
14618 emit2 ("ld %s, !*hl", _pairs[getPairId_o (result->aop, offset)].name);
14619 cost (2, 4);
14620 offset += 2;
14621 if (offset < size)
14623 emit2 ("inc %s", _pairs[pair].name);
14624 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14625 emit2 ("inc %s", _pairs[pair].name);
14626 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14627 _G.pairs[pair].offset += 2;
14629 continue;
14632 // _moveFrom_tpair_ below might use a.
14633 if (result->aop->type != AOP_REG && surviving_a && !pushed_a)
14634 _push (PAIR_AF), pushed_a = true;
14635 _moveFrom_tpair_ (result->aop, offset++, pair);
14637 if (offset < size)
14639 emit2 ("inc %s", _pairs[pair].name);
14640 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14641 _G.pairs[pair].offset++;
14644 /* Fixup HL back down */
14645 if (getPairId (left->aop) == pair && !isPairDead (pair, ic) && !pushed_pair)
14646 while (last_offset --> 0)
14648 emit2 ("dec %s", _pairs[pair].name);
14649 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14650 _G.pairs[pair].offset--;
14652 else if (rightval || result->aop->size)
14653 spillPair (pair);
14655 else
14657 size = result->aop->size;
14658 offset = 0;
14660 if (result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < offset)
14661 surviving_a = true;
14663 for (offset = 0; offset < size;)
14665 if (surviving_a && !pushed_a)
14666 _push (PAIR_AF), pushed_a = true;
14668 /* PENDING: make this better */
14669 if ((pair == PAIR_HL) && result->aop->type == AOP_REG)
14671 if (!regalloc_dry_run)
14672 aopPut (result->aop, "!*hl", offset++);
14673 ld_cost (result->aop, 0, aopInReg (result->aop, 0, A_IDX) ? ASMOP_L : ASMOP_A, 0, true);
14675 else
14677 emit2 ("ld a, !mems", _pairs[pair].name);
14678 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14679 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
14681 if (offset < size)
14683 emit2 ("inc %s", _pairs[pair].name);
14684 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14685 _G.pairs[pair].offset++;
14688 if (!isPairDead (pair, ic))
14689 while (offset --> 1)
14691 emit2 ("dec %s", _pairs[pair].name);
14692 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14693 _G.pairs[pair].offset--;
14695 else if (rightval || result->aop->size)
14696 spillPair (pair);
14699 release:
14700 if (pushed_a)
14701 _pop (PAIR_AF);
14702 if (pushed_pair)
14703 _pop (pair);
14705 freeAsmop (left, NULL);
14706 freeAsmop (result, NULL);
14709 static bool
14710 isRegOrLit (asmop * aop)
14712 if (aop->type == AOP_REG || aop->type == AOP_LIT || aop->type == AOP_IMMD)
14713 return true;
14714 return false;
14718 /*-----------------------------------------------------------------*/
14719 /* genPackBits - generates code for packed bit storage */
14720 /*-----------------------------------------------------------------*/
14721 static void
14722 genPackBits (sym_link * etype, operand * right, int pair, const iCode * ic)
14724 int offset = 0; /* source byte offset */
14725 int pair_offset = 0;
14726 int rlen = 0; /* remaining bit-field length */
14727 unsigned blen; /* bit-field length */
14728 unsigned bstr; /* bit-field starting bit within byte */
14729 unsigned long long litval; /* source literal value (if AOP_LIT) */
14730 unsigned mask; /* bitmask within current byte */
14731 int extraPair; /* a tempory register */
14732 bool needPopExtra = 0; /* need to restore original value of temp reg */
14733 unsigned int pairincrement = 0;
14735 emitDebug ("; genPackBits", "");
14737 blen = SPEC_BLEN (etype);
14738 bstr = SPEC_BSTR (etype);
14740 /* If the bit-field length is less than a byte */
14741 if (blen < 8)
14743 mask = ((0xffu << (blen + bstr)) | (0xffu >> (8 - bstr))) & 0xffu;
14745 if (right->aop->type == AOP_LIT && blen == 1 && (pair == PAIR_HL || pair == PAIR_IX || pair == PAIR_IY))
14747 litval = ullFromVal (right->aop->aopu.aop_lit);
14748 emit2 (litval & 1 ? "set %d, !mems" : "res %d, !mems", bstr, _pairs[pair].name);
14749 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 4 : 2;
14750 return;
14752 else if (right->aop->type == AOP_LIT)
14754 /* Case with a bit-field length <8 and literal source */
14755 litval = (int) ulFromVal (right->aop->aopu.aop_lit);
14756 litval <<= bstr;
14757 litval &= (~mask) & 0xff;
14758 emit2 ("ld a, !mems", _pairs[pair].name);
14759 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
14760 if ((mask | litval) != 0xff)
14762 emit2 ("and a, !immedbyte", mask);
14763 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14765 if (litval)
14767 emit2 ("or a, !immedbyte", (unsigned)litval);
14768 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14770 emit2 ("ld !mems, a", _pairs[pair].name);
14771 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
14772 return;
14774 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 || IS_Z80N || IS_R800))
14776 emit3 ((bstr ? A_RLD : A_RRD), 0, 0);
14777 cheapMove (ASMOP_A, 0, right->aop, 0, true);
14778 emit3 ((bstr ? A_RRD : A_RLD), 0, 0);
14779 return;
14781 else
14783 /* Case with a bit-field length <8 and arbitrary source */
14784 cheapMove (ASMOP_A, 0, right->aop, 0, true);
14785 /* shift and mask source value */
14786 if (blen + bstr == 8)
14787 AccLsh (bstr);
14788 else
14790 AccRol (bstr);
14791 emit2 ("and a, !immedbyte", ~mask & 0xffu);
14792 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14795 extraPair = getFreePairId (ic);
14796 if (extraPair == PAIR_INVALID)
14798 if (pair != PAIR_HL)
14799 extraPair = PAIR_HL;
14800 else
14802 extraPair = PAIR_BC;
14803 if (getPairId (right->aop) != PAIR_BC || !isLastUse (ic, right))
14805 _push (extraPair);
14806 needPopExtra = 1;
14810 emit2 ("ld %s, a", _pairs[extraPair].l);
14811 ld_cost (ASMOP_L, 0, ASMOP_A, 0, true);
14812 spillPair (extraPair);
14813 emit2 ("ld a, !mems", _pairs[pair].name);
14814 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
14816 emit2 ("and a, !immedbyte", mask);
14817 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14818 emit2 ("or a, %s", _pairs[extraPair].l);
14819 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
14820 emit2 ("ld !mems, a", _pairs[pair].name);
14821 regalloc_dry_run_cost += (pair == PAIR_IX || pair == PAIR_IY) ? 3 : 1;
14822 if (needPopExtra)
14823 _pop (extraPair);
14824 return;
14828 /* Bit length is greater than 7 bits. In this case, copy */
14829 /* all except the partial byte at the end */
14830 for (rlen = blen; rlen >= 8; rlen -= 8)
14832 cheapMove (ASMOP_A, 0, right->aop, offset++, true);
14833 if (pair == PAIR_IX || pair == PAIR_IY)
14835 emit2 ("ld %d !mems, a", pair_offset, _pairs[pair].name);
14836 regalloc_dry_run_cost += 3;
14838 else
14840 emit2 ("ld !mems, a", _pairs[pair].name);
14841 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
14843 if (rlen > 8 && pair != PAIR_IX && pair != PAIR_IY)
14845 emit2 ("inc %s", _pairs[pair].name);
14846 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14847 pairincrement++;
14848 _G.pairs[pair].offset++;
14850 else
14851 pair_offset++;
14854 /* If there was a partial byte at the end */
14855 if (rlen)
14857 mask = ((unsigned char)-1 << rlen) & 0xffu;
14859 if (right->aop->type == AOP_LIT)
14861 /* Case with partial byte and literal source */
14862 litval = ullFromVal (right->aop->aopu.aop_lit);
14863 litval >>= (blen - rlen);
14864 litval &= (~mask) & 0xff;
14866 if (pair == PAIR_IX || pair == PAIR_IY)
14868 emit2 ("ld a, %d !mems", pair_offset, _pairs[pair].name);
14869 cost2 (3, 19, 14, 9, 0, 10, 4, 5);
14871 else
14873 emit2 ("ld a, !mems", _pairs[pair].name);
14874 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
14877 if ((mask | litval) != 0xff)
14879 emit2 ("and a, !immedbyte", mask);
14880 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14882 if (litval)
14884 emit2 ("or a, !immedbyte", (unsigned)litval);
14885 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14888 else
14890 /* Case with partial byte and arbitrary source */
14891 cheapMove (ASMOP_A, 0, right->aop, offset++, true);
14892 emit2 ("and a, !immedbyte", (~mask) & 0xffu);
14893 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14895 extraPair = getFreePairId (ic);
14896 if (extraPair == PAIR_INVALID)
14898 if (pair != PAIR_HL)
14899 extraPair = PAIR_HL;
14900 else
14902 extraPair = PAIR_BC;
14903 if (getPairId (right->aop) != PAIR_BC || !isLastUse (ic, right))
14905 _push (extraPair);
14906 needPopExtra = 1;
14911 emit2 ("ld %s, a", _pairs[extraPair].l);
14912 ld_cost (ASMOP_L, 0, ASMOP_A, 0, true);
14913 spillPair (extraPair);
14915 if (pair == PAIR_IX || pair == PAIR_IY)
14917 emit2 ("ld a, %d !mems", pair_offset, _pairs[pair].name);
14918 regalloc_dry_run_cost += 3;
14920 else
14922 emit2 ("ld a, !mems", _pairs[pair].name);
14923 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
14926 emit2 ("and a, !immedbyte", mask);
14927 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
14928 emit2 ("or a, %s", _pairs[extraPair].l);
14929 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
14930 if (needPopExtra)
14931 _pop (extraPair);
14934 if (pair == PAIR_IX || pair == PAIR_IY)
14936 emit2 ("ld %d !mems, a", pair_offset, _pairs[pair].name);
14937 regalloc_dry_run_cost += 3;
14939 else
14941 emit2 ("ld !mems, a", _pairs[pair].name);
14942 regalloc_dry_run_cost += 1;
14945 if (!isPairDead(pair, ic))
14946 while (pairincrement)
14948 emit2 ("dec %s", _pairs[pair].name);
14949 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14950 pairincrement--;
14951 _G.pairs[pair].offset--;
14955 /*-----------------------------------------------------------------*/
14956 /* genPointerSet - stores the value into a pointer location */
14957 /*-----------------------------------------------------------------*/
14958 static void
14959 genPointerSet (iCode *ic)
14961 int size, offset = 0;
14962 int last_offset = 0;
14963 operand *right, *result;
14964 PAIR_ID pairId = PAIR_HL;
14965 bool pushed_a = false;
14966 bool pushed_pair = false;
14967 bool surviving_a = !isRegDead (A_IDX, ic);
14969 right = IC_RIGHT (ic);
14970 result = IC_RESULT (ic);
14972 wassert (operandType (result)->next);
14973 bool bit_field = IS_BITVAR (operandType (result)->next);
14975 aopOp (result, ic, FALSE, FALSE);
14976 aopOp (right, ic, FALSE, FALSE);
14978 size = right->aop->size;
14980 if (IS_SM83)
14981 pairId = isRegOrLit (right->aop) ? PAIR_HL : PAIR_DE;
14982 else if (IY_RESERVED)
14983 pairId = (isRegOrLit (right->aop) || right->aop->type == AOP_STK) ? PAIR_HL : PAIR_DE;
14984 if (isPair (result->aop) && isPairDead (getPairId (result->aop), ic) && !(size > 1 && sameRegs (result->aop, right->aop)))
14985 pairId = getPairId (result->aop);
14987 if (IS_SM83 && size == 1 && result->aop->type == AOP_LIT && (((unsigned long)operandLitValue (result) & 0xff00) == 0xff00) && (isRegDead (A_IDX, ic) || aopInReg (right->aop, 0, A_IDX)) && !bit_field) // SM83 has special instructions for address range 0xff00 - 0xffff.
14989 cheapMove (ASMOP_A, 0, right->aop, 0, isRegDead (A_IDX, ic));
14990 emit2 ("ldh !mems, a", aopGetLitWordLong (result->aop, 0, true));
14991 cost (2, 12);
14992 goto release;
14995 /* Handle the exceptions first */
14996 if (isPair (result->aop) && size == 1 && !bit_field)
14998 /* Just do it */
14999 const char *pair = getPairName (result->aop);
15000 if (canAssignToPtr3 (right->aop) && isPtr (pair)) // Todo: correct cost for pair iy.
15002 if (!regalloc_dry_run)
15003 emit2 ("ld !mems, %s", pair, aopGet (right->aop, 0, FALSE));
15004 if (getPairId (result->aop) == PAIR_HL)
15005 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // Assume ld (hl), r
15006 else if (aopInReg (right->aop, 0, A_IDX))
15007 cost2 (1, 7, 7, 7, 8, 6 , 2, 2); // Assume ld (rr), a
15008 else
15010 ld_cost (ASMOP_A, 0, right->aop, 0, true);
15011 cost2 (1, 7, 7, 7, 8, 6 , 2, 2); // Assume ld (rr), a
15014 else
15016 if (surviving_a && !pushed_a && !aopInReg (right->aop, 0, A_IDX))
15017 _push (PAIR_AF), pushed_a = TRUE;
15018 genMove_o (ASMOP_A, 0, right->aop, 0, 1, true,
15019 pairId != PAIR_HL && isPairDead (PAIR_HL, ic) && right->aop->regs[L_IDX] < offset && right->aop->regs[H_IDX] < offset, false, pairId != PAIR_IY && isPairDead (PAIR_IY, ic) && right->aop->regs[IYL_IDX] < offset && right->aop->regs[IYH_IDX] < offset, true);
15020 emit2 ("ld !mems, a", pair);
15021 cost2 (1, 7, 7, 7, 8, 6 , 2, 2); // Assume ld (rr), a
15023 goto release;
15026 /* Rematerialized stack location */
15027 if (result->aop->type == AOP_STL && !bit_field && size <= 4)
15029 struct asmop saop;
15030 init_stackop (&saop, size, result->aop->aopu.aop_stk);
15031 genMove (&saop, right->aop, isRegDead (A_IDX, ic), isPairDead(PAIR_HL, ic), isPairDead(PAIR_DE, ic), isPairDead(PAIR_IY, ic));
15032 goto release;
15035 // Using ldir is cheapest for large memory-to-memory transfers.
15036 // sm83 doesn't have ldir. Rabbit 2000 to Rabbit 3000 (i.e. r2k and r2ka ports) have a wait-state bug breaking ldir between different types of memory.
15037 if (!IS_SM83 && (!IS_R2K && !IS_R2KA || result->aop->type == AOP_STL) && (right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK) && size > 2)
15039 int fp_offset, sp_offset;
15041 if(!isPairDead (PAIR_DE, ic))
15042 _push (PAIR_DE);
15043 if(!isPairDead (PAIR_BC, ic))
15044 _push (PAIR_BC);
15045 if(!isPairDead (PAIR_HL, ic))
15046 _push (PAIR_HL);
15048 fetchPair (PAIR_DE, result->aop);
15050 fp_offset = right->aop->aopu.aop_stk + (right->aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0);
15051 sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
15052 emit2 ("!ldahlsp", sp_offset);
15053 regalloc_dry_run_cost += 4;
15054 emit2 ("ld bc, !immedword", (unsigned)size);
15055 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
15056 emit2 ("ldir");
15057 cost2 (2, 21 * size - 5, 14 * size - 2, 7 * size - 1, 0, 18 * size - 4, 2 * size - 1, 4 * size);
15058 spillPair (PAIR_HL);
15060 if(!isPairDead (PAIR_HL, ic))
15061 _pop (PAIR_HL);
15062 if(!isPairDead (PAIR_BC, ic))
15063 _pop (PAIR_BC);
15064 if(!isPairDead (PAIR_DE, ic))
15065 _pop (PAIR_DE);
15066 goto release;
15069 if (getPairId (result->aop) == PAIR_IY && !bit_field)
15071 /* Just do it */
15072 while (size--)
15074 if (canAssignToPtr3 (right->aop))
15076 if (!regalloc_dry_run)
15077 emit2 ("ld !*iyx, %s", offset, aopGet (right->aop, offset, FALSE));
15078 if (right->aop->type == AOP_LIT)
15079 cost2 (4, 19, 15, 11, 0, 12, 5, 5); // ld d (iy), n
15080 else
15081 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d (iy), r
15083 else
15085 cheapMove (ASMOP_A, 0, right->aop, offset, true);
15086 emit2 ("ld !*iyx, a", offset);
15087 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d (iy), r
15089 offset++;
15091 goto release;
15093 else if (getPairId (result->aop) == PAIR_HL && !isPairDead (PAIR_HL, ic) && !bit_field)
15095 while (offset < size)
15097 last_offset = offset;
15099 if (IS_EZ80_Z80 && offset + 1 < size && getPairId_o (right->aop, offset) != PAIR_INVALID)
15101 emit2 ("ld !mems, %s", _pairs[PAIR_HL].name, _pairs[getPairId_o (right->aop, offset)].name);
15102 regalloc_dry_run_cost += 2;
15103 offset += 2;
15105 if (offset < size)
15107 emit3w (A_INC, ASMOP_HL, 0);
15108 emit3w (A_INC, ASMOP_HL, 0);
15109 _G.pairs[PAIR_HL].offset++;
15112 continue;
15114 else if (isRegOrLit (right->aop) && !IS_SM83)
15116 if (!regalloc_dry_run)
15117 emit2 ("ld !mems, %s", _pairs[PAIR_HL].name, aopGet (right->aop, offset, FALSE));
15118 ld_cost (aopInReg (right->aop, offset, A_IDX) ? ASMOP_L : ASMOP_A, 0, right->aop, offset, true);
15119 offset++;
15121 else
15123 if (surviving_a && !pushed_a && (!aopInReg (right->aop, 0, A_IDX) || offset))
15124 _push (PAIR_AF), pushed_a = TRUE;
15125 genMove_o (ASMOP_A, 0, right->aop, offset, 1, true, false, false, false, true);
15126 emit2 ("ld !mems, a", _pairs[PAIR_HL].name);
15127 cost2 (1 + IS_TLCS90, 7, 7, 6, 8, 6, 2, 2);
15128 offset++;
15131 if (offset < size)
15133 emit3w (A_INC, ASMOP_HL, 0);
15134 _G.pairs[PAIR_HL].offset++;
15138 /* Fixup HL back down */
15139 while (last_offset --> 0)
15140 emit3w (A_DEC, ASMOP_HL, 0);
15141 goto release;
15144 if (!IS_SM83 && !bit_field && isLitWord (result->aop) && size == 2 && offset == 0 && !sameRegs (result->aop, right->aop) &&
15145 (right->aop->type == AOP_REG && getPairId (right->aop) != PAIR_INVALID || isLitWord (right->aop) && (isPairDead (PAIR_HL, ic) || isPairDead (PAIR_DE, ic) || isPairDead (PAIR_BC, ic))))
15147 if (isLitWord (right->aop))
15149 pairId = isPairDead (PAIR_HL, ic) ? PAIR_HL : isPairDead (PAIR_DE, ic) ? PAIR_DE : PAIR_BC;
15150 fetchPairLong (pairId, right->aop, ic, 0);
15152 else
15153 pairId = getPairId (right->aop);
15154 emit2 ("ld !mems, %s", aopGetLitWordLong (result->aop, offset, FALSE), _pairs[pairId].name);
15155 if (!IS_TLCS90 && pairId == PAIR_HL)
15156 cost2 (3, 16, 16, 13, 0, 0, 5, 5);
15157 else
15158 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
15159 goto release;
15161 if (!IS_SM83 && !bit_field && isLitWord (result->aop) && size == 4 && offset == 0 &&
15162 (getPartPairId (right->aop, 0) != PAIR_INVALID && getPartPairId (right->aop, 2) != PAIR_INVALID || isLitWord (right->aop)))
15164 if (isLitWord (right->aop))
15166 pairId = PAIR_HL;
15167 fetchPairLong (pairId, right->aop, ic, 0);
15169 else
15170 pairId = getPartPairId (right->aop, 0);
15171 emit2 ("ld !mems, %s", aopGetLitWordLong (result->aop, offset, FALSE), _pairs[pairId].name);
15172 if (!IS_TLCS90 && pairId == PAIR_HL)
15173 cost2 (3, 16, 16, 13, 0, 0, 5, 5);
15174 else
15175 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
15176 if (isLitWord (right->aop))
15178 pairId = PAIR_HL;
15179 fetchPairLong (pairId, right->aop, ic, 2);
15181 else
15182 pairId = getPartPairId (right->aop, 2);
15183 emit2 ("ld (%s+%d), %s", aopGetLitWordLong (result->aop, offset, FALSE),2, _pairs[pairId].name); // Handling of literal addresses is somewhat broken, use explicit offset as workaround.
15184 regalloc_dry_run_cost += (pairId == PAIR_HL) ? 3 : 4;
15185 goto release;
15188 if (getPairId (result->aop) != pairId &&
15189 (right->aop->regs[_pairs[pairId].l_idx] >= 0 || right->aop->regs[_pairs[pairId].h_idx] >= 0))
15190 UNIMPLEMENTED;
15192 /* if the operand is already in dptr
15193 then we do nothing else we move the value to dptr */
15194 if (bit_field && getPairId (result->aop) != PAIR_INVALID && (getPairId (result->aop) != PAIR_IY || SPEC_BLEN (getSpec (operandType (result)->next)) < 8 || isPairDead (getPairId (result->aop), ic))) /* Avoid destroying result by increments */
15195 pairId = getPairId (result->aop);
15196 else
15198 if (!isPairDead (pairId, ic) && getPairId (result->aop) != pairId)
15200 _push (pairId);
15201 pushed_pair = true;
15203 genMove (pairId == PAIR_HL ? ASMOP_HL : pairId == PAIR_DE ? ASMOP_DE : ASMOP_BC, result->aop,
15204 isRegDead(A_IDX, ic) && right->aop->regs[A_IDX] < 0,
15205 isPairDead (PAIR_HL, ic) && right->aop->regs[L_IDX] < 0 && right->aop->regs[H_IDX] < 0,
15206 isPairDead (PAIR_DE, ic) && right->aop->regs[E_IDX] < 0 && right->aop->regs[D_IDX] < 0,
15207 isPairDead (PAIR_IY, ic) && right->aop->regs[IYL_IDX] < 0 && right->aop->regs[IYH_IDX] < 0);
15209 /* so hl now contains the address */
15210 /*freeAsmop (result, NULL, ic);*/
15212 /* if bit then pack */
15213 if (bit_field)
15215 genPackBits (getSpec (operandType (result)->next), right, pairId, ic);
15216 goto release;
15218 else
15220 bool zero_a = false;
15222 for (offset = 0; offset < size;)
15224 last_offset = offset;
15226 if (IS_EZ80_Z80 && offset + 1 < size && pairId == PAIR_HL && getPairId_o (right->aop, offset) != PAIR_INVALID)
15228 emit2 ("ld !mems, %s", _pairs[pairId].name, _pairs[getPairId_o (right->aop, offset)].name);
15229 regalloc_dry_run_cost += 2;
15230 offset += 2;
15232 if (offset < size)
15234 emit2 ("inc %s", _pairs[pairId].name);
15235 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
15236 emit2 ("inc %s", _pairs[pairId].name);
15237 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
15238 _G.pairs[pairId].offset++;
15241 continue;
15244 if (!zero_a && offset + 1 < size && aopIsLitVal (right->aop, offset, 2, 0x0000) && !surviving_a)
15246 emit2 ("xor a, a");
15247 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
15248 zero_a = true;
15251 if (aopIsLitVal (right->aop, offset, 1, 0x00) && zero_a)
15253 emit2 ("ld !mems, a", _pairs[pairId].name);
15254 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
15256 else if (isRegOrLit (right->aop) && pairId == PAIR_HL)
15258 if (!regalloc_dry_run)
15259 emit2 ("ld !mems, %s", _pairs[pairId].name, aopGet (right->aop, offset, FALSE));
15260 ld_cost (aopInReg (right->aop, offset, A_IDX) ? ASMOP_L : ASMOP_A, 0, right->aop, offset, true);
15262 else
15264 if (surviving_a && !pushed_a && (!aopInReg (right->aop, 0, A_IDX) || offset))
15265 _push (PAIR_AF), pushed_a = true;
15266 genMove_o (ASMOP_A, 0, right->aop, offset, 1, true,
15267 pairId != PAIR_HL && isPairDead (PAIR_HL, ic) && right->aop->regs[L_IDX] < offset && right->aop->regs[H_IDX] < offset, false, pairId != PAIR_IY && isPairDead (PAIR_IY, ic) && right->aop->regs[IYL_IDX] < offset && right->aop->regs[IYH_IDX] < offset, true);
15268 zero_a = false;
15269 emit2 ("ld !mems, a", _pairs[pairId].name);
15270 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
15272 offset++;
15274 if (offset < size)
15276 if (right->aop->regs[_pairs[pairId].l_idx] >= offset || right->aop->regs[_pairs[pairId].h_idx] >= offset)
15277 UNIMPLEMENTED;
15278 emit2 ("inc %s", _pairs[pairId].name);
15279 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
15280 _G.pairs[pairId].offset++;
15283 /* Restore operand in pair. */
15284 if (!isPairDead (pairId, ic) && getPairId (result->aop) == pairId)
15285 while(last_offset --> 0)
15287 emit2 ("dec %s", _pairs[pairId].name);
15288 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
15289 _G.pairs[pairId].offset--;
15292 release:
15293 if (pushed_pair)
15294 _pop (pairId);
15295 if (pushed_a)
15296 _pop (PAIR_AF);
15298 freeAsmop (right, NULL);
15299 freeAsmop (result, NULL);
15302 /*-----------------------------------------------------------------*/
15303 /* genIfx - generate code for Ifx statement */
15304 /*-----------------------------------------------------------------*/
15305 static void
15306 genIfx (iCode *ic, iCode *popIc)
15308 operand *cond = IC_COND (ic);
15309 int isbit = 0;
15311 aopOp (cond, ic, FALSE, TRUE);
15313 /* Special case: Condition is bool */
15314 if (IS_BOOL (operandType (cond)) && !aopInReg (cond->aop, 0, A_IDX) && !aopInReg (cond->aop, 0, IYL_IDX) && !aopInReg (cond->aop, 0, IYH_IDX))
15316 if (!regalloc_dry_run)
15318 emit2 ("bit 0, %s", aopGet (cond->aop, 0, FALSE));
15319 genIfxJump (ic, "nz");
15321 bit8_cost (cond->aop); // todo: fix, bit has different cost!
15323 goto release;
15325 else if (cond->aop->size == 1 && !isRegDead (A_IDX, ic) &&
15326 (aopInReg (cond->aop, 0, B_IDX) || aopInReg (cond->aop, 0, C_IDX) || aopInReg (cond->aop, 0, D_IDX) || aopInReg (cond->aop, 0, E_IDX) || aopInReg (cond->aop, 0, H_IDX) || aopInReg (cond->aop, 0, L_IDX)))
15328 emit3 (A_INC, cond->aop, 0);
15329 emit3 (A_DEC, cond->aop, 0);
15330 genIfxJump (ic, "nz");
15332 goto release;
15334 else if (IS_RAB && (getPairId (cond->aop) == PAIR_HL || getPairId (cond->aop) == PAIR_IY) && isPairDead (getPairId (cond->aop), ic))
15336 emit2 ("bool %s", _pairs[getPairId (cond->aop)].name);
15337 cost (1 + (getPairId (cond->aop) == PAIR_IY), 2 + 2 * (getPairId (cond->aop) == PAIR_IY));
15338 genIfxJump (ic, "nz");
15340 goto release;
15342 /* get the value into acc */
15343 else if (cond->aop->type != AOP_CRY)
15344 _toBoolean (cond, !popIc);
15345 else
15346 isbit = 1;
15347 /* the result is now in the accumulator */
15348 freeAsmop (cond, NULL);
15350 /* if the condition is a bit variable */
15351 if (isbit && IS_ITEMP (cond) && SPIL_LOC (cond))
15352 genIfxJump (ic, SPIL_LOC (cond)->rname);
15353 else if (isbit && !IS_ITEMP (cond))
15354 genIfxJump (ic, OP_SYMBOL (cond)->rname);
15355 else
15356 genIfxJump (ic, popIc ? "a" : "nz");
15358 return;
15360 release:
15362 freeAsmop (cond, NULL);
15364 return;
15367 /*-----------------------------------------------------------------*/
15368 /* genAddrOf - generates code for address of */
15369 /*-----------------------------------------------------------------*/
15370 static void
15371 genAddrOf (const iCode * ic)
15373 symbol *sym;
15374 PAIR_ID pair;
15375 operand *right = IC_RIGHT (ic);
15376 wassert (IS_TRUE_SYMOP (IC_LEFT (ic)));
15377 wassert (right && IS_OP_LITERAL (IC_RIGHT (ic)));
15378 sym = OP_SYMBOL (IC_LEFT (ic));
15379 aopOp (IC_RESULT (ic), ic, true, false);
15381 if (sym->onStack)
15383 int fp_offset = sym->stack + (sym->stack > 0 ? _G.stack.param_offset : 0) + (int)operandLitValue (right);
15384 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
15385 bool in_fp_range = !_G.omitFramePtr && (fp_offset >= -128 && fp_offset < 128);
15387 if (IS_EZ80_Z80 && in_fp_range && getPairId (IC_RESULT (ic)->aop) != PAIR_INVALID)
15388 pair = getPairId (IC_RESULT (ic)->aop);
15389 else
15390 pair = (getPairId (IC_RESULT (ic)->aop) == PAIR_IY) ? PAIR_IY : PAIR_HL;
15391 spillPair (pair);
15392 if ((IS_TLCS90 || IS_EZ80_Z80) && in_fp_range)
15394 emit2 (IS_TLCS90 ? "lda %s, ix, !immed%d" : "lea %s, ix, !immed%d", _pairs[pair].name, fp_offset);
15395 cost (3, IS_TLCS90 ? 10 : 3);
15397 else
15398 setupPairFromSP (pair, sp_offset);
15400 else
15402 pair = getPairId (IC_RESULT (ic)->aop);
15403 if (pair == PAIR_INVALID)
15405 pair = IS_SM83 ? PAIR_DE : PAIR_HL;
15406 spillPair (pair);
15408 emit2 ("ld %s, !hashedstr+%ld", _pairs[pair].name, sym->rname, (long)(operandLitValue (right)));
15409 if (pair == PAIR_IY)
15410 cost2 (4 - IS_TLCS90, 14, 12, 8, 0, 6, 4, 4);
15411 else
15412 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
15415 commitPair (IC_RESULT (ic)->aop, pair, ic, FALSE);
15417 freeAsmop (IC_RESULT (ic), NULL);
15420 /*-----------------------------------------------------------------*/
15421 /* genAssign - generate code for assignment */
15422 /*-----------------------------------------------------------------*/
15423 static void
15424 genAssign (const iCode *ic)
15426 operand *result, *right;
15427 int size, offset;
15429 result = IC_RESULT (ic);
15430 right = IC_RIGHT (ic);
15432 const bool hl_dead = isPairDead (PAIR_HL, ic);
15434 /* Dont bother assigning if they are the same */
15435 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
15436 return;
15438 aopOp (right, ic, FALSE, FALSE);
15439 aopOp (result, ic, TRUE, FALSE);
15441 /* if they are the same registers */
15442 if (sameRegs (right->aop, result->aop))
15444 emitDebug ("; (locations are the same)");
15445 goto release;
15448 /* if the result is a bit */
15449 if (result->aop->type == AOP_CRY)
15451 wassertl (0, "Tried to assign to a bit");
15454 /* general case */
15455 size = result->aop->size;
15456 offset = 0;
15458 // SM83 has special instruction for access to addresses 0xff00 to 0xffff, so use them here, when possible
15459 if (IS_SM83 && size == 1 && aopInReg (result->aop, 0, A_IDX) && right->aop->type == AOP_HL && SPEC_ABSA (OP_SYM_ETYPE (right)) && (SPEC_ADDR (OP_SYM_ETYPE (right)) & 0xff00) == 0xff00)
15461 emit2 ("ldh a, !mems", right->aop->aopu.aop_dir);
15462 cost (2, 12);
15463 goto release;
15465 else if (IS_SM83 && size == 1 && aopInReg (right->aop, 0, A_IDX) && result->aop->type == AOP_HL && SPEC_ABSA (OP_SYM_ETYPE (result)) && (SPEC_ADDR (OP_SYM_ETYPE (result)) & 0xff00) == 0xff00)
15467 emit2 ("ldh (#%x), a", result->aop->aopu.aop_dir);
15468 cost (2, 12);
15469 goto release;
15472 if (isPair (result->aop) && getPairId (result->aop) != PAIR_IY ||
15473 isPair (right->aop) && result->aop->type == AOP_IY && size == 2)
15474 genMove (result->aop, right->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), true);
15475 else if (size == 2 && isPairDead (PAIR_HL, ic) &&
15476 (!IS_SM83 && (right->aop->type == AOP_STK && !_G.omitFramePtr || right->aop->type == AOP_IY || right->aop->type == AOP_LIT) && result->aop->type == AOP_IY || // Use ld (nn), hl
15477 !IS_SM83 && right->aop->type == AOP_IY && (result->aop->type == AOP_STK && !_G.omitFramePtr || result->aop->type == AOP_IY) || // Use ld hl, (nn)
15478 !IS_SM83 && right->aop->type == AOP_LIT && (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK) && (result->aop->aopu.aop_stk + offset + _G.stack.offset + (result->aop->aopu.aop_stk > 0 ? _G.stack.param_offset : 0) + _G.stack.pushed) == 0 || // Use ex (sp), hl
15479 (IS_RAB || IS_TLCS90) && (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK) && (right->aop->type == AOP_LIT || right->aop->type == AOP_IMMD))) // Use ld d(sp), hl
15481 fetchPair (PAIR_HL, right->aop);
15482 genMove (result->aop, ASMOP_HL, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15484 else if (size == 2 && getPairId (right->aop) != PAIR_INVALID)
15485 genMove (result->aop, right->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15486 else if (size <= 2 && requiresHL (right->aop) && requiresHL (result->aop) && IS_SM83)
15487 genMove (result->aop, right->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15488 else if (getPairId (right->aop) == PAIR_IY && result->aop->type != AOP_REG)
15490 while (size--)
15492 if (size == 0)
15494 if (IS_TLCS90) // f needs to be preserved for tlcs90.
15496 emit2 ("push iy");
15497 emit2 ("ld a, 0(sp)");
15498 emit2 ("inc sp");
15499 emit2 ("inc sp");
15500 cost (5, 26);
15502 else
15504 emit2 ("push iy");
15505 emit2 ("dec sp");
15506 emit2 ("pop af");
15507 emit2 ("inc sp");
15508 regalloc_dry_run_cost += 5;
15510 if (result->aop->type == AOP_IY) /* Take care not to overwrite iy */
15512 emit2 ("ld (%s+%d), a", result->aop->aopu.aop_dir, size);
15513 cost2 (3, 13, 13, 10, 16, 10, 4, 4);
15515 else
15516 cheapMove (result->aop, size, ASMOP_A, 0, true);
15518 else if (size == 1)
15520 if (result->aop->type == AOP_IY) /* Take care not to overwrite iy */
15522 emit2 ("ld !mems, iy", result->aop->aopu.aop_dir);
15523 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
15524 size--;
15526 else if (result->aop->type == AOP_EXSTK || IS_TLCS90) /* Take care not to overwrite iy or f */
15528 bool pushed_pair = FALSE;
15529 PAIR_ID pair = getDeadPairId (ic);
15530 if (pair == PAIR_INVALID)
15532 pair = PAIR_HL;
15533 _push(pair);
15534 pushed_pair= TRUE;
15536 fetchPair (pair, right->aop);
15537 commitPair (result->aop, pair, ic, FALSE);
15538 if (pushed_pair)
15539 _pop (pair);
15540 size--;
15542 else
15544 _push (PAIR_IY);
15545 _pop (PAIR_AF);
15546 cheapMove (result->aop, size, ASMOP_A, 0, true);
15549 else
15551 if (result->aop->type == AOP_IY) /* Take care not to overwrite iy */
15553 cheapMove (ASMOP_A, 0, ASMOP_ZERO, 0, true);
15554 emit2 ("ld (%s+%d), a", result->aop->aopu.aop_dir, size);
15555 cost2 (3, 13, 13, 10, 16, 10, 4, 4);
15557 else
15558 cheapMove (result->aop, size, ASMOP_ZERO, 0, true);
15562 else if (size == 4 && (requiresHL (right->aop) && right->aop->type != AOP_REG) && (requiresHL (result->aop) && result->aop->type != AOP_REG ) && isPairDead (PAIR_DE, ic) && (IS_SM83 || IY_RESERVED))
15564 /* Special case - simple memcpy */
15565 if (!regalloc_dry_run)
15567 aopGet (right->aop, LSB, FALSE);
15568 emit2 ("ld d, h");
15569 emit2 ("ld e, l");
15570 aopGet (result->aop, LSB, FALSE);
15572 regalloc_dry_run_cost += 8; // Todo: More exact cost here!
15574 while (size--)
15576 emit2 ("ld a, !mems", "de");
15577 cost2 (1 + IS_TLCS90, 7, 6, 6, 8, 6, 2, 2);
15578 if (size != 0)
15580 emit2 ("!lldahli");
15581 emit2 ("inc de");
15582 regalloc_dry_run_cost += 3;
15584 else
15586 emit2 ("ld !*hl, a");
15587 cost2 (1 + IS_TLCS90, 7, 7, 7, 8, 6, 2, 2);
15590 spillPair (PAIR_HL);
15592 else
15594 // ldir could overwrite if areas overlap.
15595 bool down = false;
15596 if ((result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK) &&
15597 (right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK))
15598 if (!regalloc_dry_run && result->aop->aopu.aop_stk > right->aop->aopu.aop_stk && result->aop->aopu.aop_stk < right->aop->aopu.aop_stk + size)
15599 down = true;
15601 if (!IS_SM83 && !down && // sm83 doesn't have ldir, Rabbit 2000 to Rabbit 3000 (i.e. r2k and r2ka ports) ldir is affected by a wait state bug when copying between different types of memory.
15602 (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK || result->aop->type == AOP_DIR
15603 || result->aop->type == AOP_IY) && (right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK
15604 || right->aop->type == AOP_DIR || right->aop->type == AOP_IY) && size >= 2)
15606 // This estimation is only accurate, if neither operand is AOP_EXSTK, and we are optimizing for code size or targeting the Z80, Z180, eZ80, Z80N or Rabbit 3000A.
15607 int sizecost_n, sizecost_l, cyclecost_n, cyclecost_l;
15608 const bool hl_alive = !isPairDead (PAIR_HL, ic);
15609 const bool de_alive = !isPairDead (PAIR_DE, ic);
15610 const bool bc_alive = !isPairDead (PAIR_BC, ic);
15611 bool l_better;
15613 if (IS_EZ80_Z80 && result->aop->type == AOP_STK && right->aop->type == AOP_STK) // eZ80: Use 16-Bit loads, except for odd trailing byte.
15614 sizecost_n = (size / 2 * 6) + (size % 2 * 6);
15615 else if (IS_RAB && result->aop->type == AOP_STK && right->aop->type == AOP_STK) // Rabbit: Use 16-Bit loads, except for odd trailing byte.
15616 sizecost_n = (size / 2 * 4) + (size % 2 * 6);
15617 else // Use 8-Bit loads: Z80, Z180, Z80N.
15618 sizecost_n = 6 * size;
15620 sizecost_l = 13 + hl_alive * 2 + de_alive * 2 + bc_alive * 2 -
15621 (right->aop->type == AOP_DIR || right->aop->type == AOP_IY) -
15622 (result->aop->type == AOP_DIR || result->aop->type == AOP_IY) * 2;
15624 if (IS_EZ80_Z80 && result->aop->type == AOP_STK && right->aop->type == AOP_STK)
15625 cyclecost_n = (size / 2 * 10) + (size % 2 * 8);
15626 else if (IS_RAB && result->aop->type == AOP_STK && right->aop->type == AOP_STK)
15627 cyclecost_n = (size / 2 * 18) + (size % 2 * 18);
15628 else if (IS_EZ80_Z80)
15629 cyclecost_n = 8 * size;
15630 else if (IS_Z180)
15631 cyclecost_n = 30 * size;
15632 else if (IS_RAB)
15633 cyclecost_n = 18 * size;
15634 else // Z80, Z80N
15635 cyclecost_n = 38 * size;
15637 if (IS_EZ80_Z80)
15638 cyclecost_l = 2 * size + 9 + hl_alive * 6 + de_alive * 6 + bc_alive * 6; // lea is as fast as ld rr, nn. So it does not matter if the operands are on stack.
15639 else if (IS_Z180)
15640 cyclecost_l = 14 * size + 42 + hl_alive * 22 + de_alive * 22 + bc_alive * 22 -
15641 (right->aop->type == AOP_DIR || right->aop->type == AOP_IY) * 7 -
15642 (result->aop->type == AOP_DIR || result->aop->type == AOP_IY) * 10;
15643 else if (IS_RAB)
15644 cyclecost_l = 7 * size + 34 + hl_alive * 17 + de_alive * 17 + bc_alive * 17 -
15645 (right->aop->type == AOP_DIR || right->aop->type == AOP_IY) * 4 -
15646 (result->aop->type == AOP_DIR || result->aop->type == AOP_IY) * 6;
15647 else // Z80
15648 cyclecost_l = 21 * size + 51 + hl_alive * 21 + de_alive * 21 + bc_alive * 21 -
15649 (right->aop->type == AOP_DIR || right->aop->type == AOP_IY) * 11 -
15650 (result->aop->type == AOP_DIR || result->aop->type == AOP_IY) * 15;
15652 if (optimize.codeSize)
15653 l_better = (sizecost_l < sizecost_n || sizecost_l == sizecost_n && cyclecost_l < cyclecost_n);
15654 else
15655 l_better = (cyclecost_l < cyclecost_n || cyclecost_l == cyclecost_n && sizecost_l < sizecost_n);
15657 if (l_better)
15659 if (hl_alive)
15660 _push (PAIR_HL);
15661 if (de_alive)
15662 _push (PAIR_DE);
15663 if (bc_alive)
15664 _push (PAIR_BC);
15666 if (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK)
15668 int fp_offset =
15669 result->aop->aopu.aop_stk + offset + (result->aop->aopu.aop_stk >
15670 0 ? _G.stack.param_offset : 0);
15671 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
15672 emit2 ("!ldahlsp", sp_offset);
15673 regalloc_dry_run_cost += 4;
15674 emit3w (A_EX, ASMOP_DE, ASMOP_HL);
15676 else
15677 pointPairToAop (PAIR_DE, result->aop, 0);
15679 if (right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK)
15681 int fp_offset =
15682 right->aop->aopu.aop_stk + offset + (right->aop->aopu.aop_stk >
15683 0 ? _G.stack.param_offset : 0);
15684 int sp_offset = fp_offset + _G.stack.pushed + _G.stack.offset;
15685 emit2 ("!ldahlsp", sp_offset);
15686 spillPair (PAIR_HL);
15687 regalloc_dry_run_cost += 4;
15689 else
15690 pointPairToAop (PAIR_HL, right->aop, 0);
15692 if (size <= 2 + (!IS_RAB && optimize.codeSpeed) ||
15693 // Early Rabbits (up to Rabbit 3000) have a wait state bug when ldir copies between different types of memory.
15694 (IS_R2K || IS_R2KA) && !((right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK) && (result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK)))
15695 for(int i = 0; i < size; i++)
15697 emit2 ("ldi");
15698 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
15700 else
15702 emit2 ("ld bc, !immed%d", size);
15703 emit2 ("ldir");
15704 regalloc_dry_run_cost += 5;
15706 spillPair (PAIR_HL);
15707 spillPair (PAIR_DE);
15708 spillPair (PAIR_BC);
15710 if (bc_alive)
15711 _pop (PAIR_BC);
15712 if (de_alive)
15713 _pop (PAIR_DE);
15714 if (hl_alive)
15715 _pop (PAIR_HL);
15717 goto release;
15720 if ((result->aop->type == AOP_REG || result->aop->type == AOP_STK || result->aop->type == AOP_EXSTK || result->aop->type == AOP_IY || result->aop->type == AOP_HL) && (right->aop->type == AOP_REG || right->aop->type == AOP_STK || right->aop->type == AOP_EXSTK || right->aop->type == AOP_LIT || right->aop->type == AOP_IMMD || right->aop->type == AOP_DIR || right->aop->type == AOP_IY || right->aop->type == AOP_HL))
15721 genMove (result->aop, right->aop, isRegDead (A_IDX, ic), isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15722 else
15723 while (size--)
15725 const bool hl_free = hl_dead &&
15726 (right->aop->regs[L_IDX] <= offset) && (right->aop->regs[H_IDX] <= offset) &&
15727 (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= offset) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= offset);
15728 const bool save_hl = !hl_free && ((IS_SM83 || IY_RESERVED) && (requiresHL (right->aop) || requiresHL (result->aop)));
15730 if (save_hl)
15731 _push (PAIR_HL);
15732 cheapMove (result->aop, offset, right->aop, offset, isRegDead (A_IDX, ic));
15733 if (save_hl)
15735 _pop (PAIR_HL);
15736 spillPair (PAIR_HL);
15738 offset++;
15742 release:
15743 freeAsmop (right, NULL);
15744 freeAsmop (result, NULL);
15747 /*-----------------------------------------------------------------*/
15748 /* genJumpTab - generate code for jump table */
15749 /*-----------------------------------------------------------------*/
15750 static void
15751 genJumpTab (const iCode *ic)
15753 symbol *jtab = NULL;
15754 operand *jtcond = IC_JTCOND (ic);
15755 bool pushed_pair = false;
15756 PAIR_ID pair;
15758 aopOp (jtcond, ic, false, false);
15760 wassert (isPairDead (PAIR_HL, ic));
15762 if (!regalloc_dry_run)
15763 jtab = newiTempLabel (NULL);
15765 if (IS_TLCS90 && // Use lda hl, hl, a
15766 (jtcond->aop->size == 1 || aopIsLitVal (jtcond->aop, 1, jtcond->aop->size - 1, 0)) &&
15767 (isRegDead (A_IDX, ic) || aopInReg (jtcond->aop, 0, A_IDX)) &&
15768 !aopInReg (jtcond->aop, 0, C_IDX) && !aopInReg (jtcond->aop, 0, E_IDX))
15771 genMove (ASMOP_A, jtcond->aop, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15772 if (!regalloc_dry_run)
15773 emit2 ("ld hl, !immed!tlabel", labelKey2num (jtab->key));
15774 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
15775 emit2 ("lda hl, hl, a");
15776 cost (2, 14);
15777 emit2 ("ld hl, a(hl)");
15778 cost (2 , 16);
15779 goto jump;
15782 // Choose extra pair DE or BC for addition
15783 if (jtcond->aop->type == AOP_REG && jtcond->aop->aopu.aop_reg[0]->rIdx == E_IDX && isPairDead (PAIR_DE, ic))
15784 pair = PAIR_DE;
15785 else if (jtcond->aop->type == AOP_REG && jtcond->aop->aopu.aop_reg[0]->rIdx == C_IDX && isPairDead (PAIR_BC, ic))
15786 pair = PAIR_BC;
15787 else if ((pair = getDeadPairId (ic)) == PAIR_INVALID)
15788 pair = PAIR_DE;
15790 if (!isPairDead (pair, ic))
15792 _push (pair);
15793 pushed_pair = true;
15796 genMove (pair == PAIR_DE ? ASMOP_DE : ASMOP_BC, jtcond->aop, isRegDead (A_IDX, ic), true, isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15798 if (!regalloc_dry_run)
15799 emit2 ("ld hl, !immed!tlabel", labelKey2num (jtab->key));
15800 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
15801 emit2 ("add hl, %s", _pairs[pair].name);
15802 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
15803 emit2 ("add hl, %s", _pairs[pair].name);
15804 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
15805 spillPair (PAIR_HL);
15807 if (IS_TLCS90 || IS_EZ80_Z80)
15809 emit2 ("ld hl, (hl)");
15810 cost (2, IS_TLCS90 ? 8 : 4);
15812 else if (IS_RAB)
15814 emit2 ("ld hl, 0(hl)");
15815 cost (3, 11);
15817 else
15819 emit2 ("ld %s, !*hl", _pairs[pair].l);
15820 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
15821 emit2 ("inc hl");
15822 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
15823 emit2 ("ld h, !*hl");
15824 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
15825 emit3 (A_LD, ASMOP_L, pair == PAIR_DE ? ASMOP_E : ASMOP_C);
15828 jump:
15829 if (pushed_pair)
15830 _pop (pair);
15832 emit2 ("!jphl");
15833 cost2 (1 + IS_TLCS90, 4, 3, 4, 4, 8, 3, 1);
15835 if (!regalloc_dry_run)
15837 emitLabelSpill (jtab);
15838 for (jtab = setFirstItem (IC_JTLABELS (ic)); jtab; jtab = setNextItem (IC_JTLABELS (ic)))
15839 emit2 (".dw !tlabel", labelKey2num (jtab->key));
15841 // regalloc_dry_run_cost += 3 // doesn't matter and might overflow cost
15843 freeAsmop (IC_JTCOND (ic), NULL);
15846 /*-----------------------------------------------------------------*/
15847 /* genCast - gen code for casting */
15848 /*-----------------------------------------------------------------*/
15849 static void
15850 genCast (const iCode *ic)
15852 operand *result = IC_RESULT (ic);
15853 operand *right = IC_RIGHT (ic);
15854 sym_link *resulttype = operandType (result);
15855 sym_link *righttype = operandType (right);
15856 int size;
15857 bool surviving_a = !isRegDead (A_IDX, ic);
15858 bool pushed_a = FALSE;
15860 /* if they are equivalent then do nothing */
15861 if (operandsEqu (IC_RESULT (ic), IC_RIGHT (ic)))
15862 return;
15864 aopOp (right, ic, false, false);
15865 aopOp (result, ic, true, false);
15867 /* if the result is a bit */
15868 if (result->aop->type == AOP_CRY)
15870 wassertl (0, "Tried to cast to a bit");
15873 unsigned topbytemask = (IS_BITINT (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8)) ?
15874 (0xff >> (8 - SPEC_BITINTWIDTH (resulttype) % 8)) : 0xff;
15876 // Cast to _BitInt can require mask of top byte.
15877 if (IS_BITINT (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8) && bitsForType (resulttype) < bitsForType (righttype))
15879 if (!isRegDead (A_IDX, ic) || result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] != result->aop->size - 1)
15880 _push (PAIR_AF), pushed_a = true;
15881 genMove (result->aop, right->aop, true, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic));
15882 cheapMove (ASMOP_A, 0, result->aop, result->aop->size - 1, true);
15883 emit2 ("and a, #0x%02x", topbytemask);
15884 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
15885 if (!SPEC_USIGN (resulttype)) // Sign-extend
15887 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
15888 emit2 ("bit %d, a", (int)(SPEC_BITINTWIDTH (resulttype) % 8 - 1));
15889 cost2 (2, 8, 6, 4, 8, 4, 2, 2);
15890 if (!regalloc_dry_run)
15891 emit2 ("jr z, !tlabel", labelKey2num (tlbl->key));
15892 emit2 ("or a, #0x%02x", ~topbytemask & 0xffu);
15893 regalloc_dry_run_cost += 4;
15894 emitLabel (tlbl);
15896 cheapMove (result->aop, result->aop->size - 1, ASMOP_A, 0, true);
15898 goto release;
15901 /* casting to bool */
15902 if (IS_BOOL (resulttype) && IS_RAB && right->aop->size == 2 &&
15903 (aopInReg (right->aop, 0, HL_IDX) && isPairDead (PAIR_HL, ic) || aopInReg (right->aop, 0, IY_IDX) && isPairDead (PAIR_IY, ic)))
15905 bool iy = aopInReg (right->aop, 0, IY_IDX);
15906 emit2 ("bool %s", _pairs[getPairId (right->aop)].name);
15907 cheapMove (result->aop, 0, iy ? ASMOP_IYL : ASMOP_L, 0, isRegDead (A_IDX, ic));
15908 goto release;
15910 if (IS_BOOL (resulttype))
15912 _castBoolean (right);
15913 outAcc (result);
15914 goto release;
15917 /* if they are the same size or less */
15918 if (result->aop->size <= right->aop->size)
15920 genAssign (ic);
15921 goto release;
15924 // Now we know that the size of destination is greater than the size of the source
15926 /* now depending on the sign of the destination */
15927 size = result->aop->size - right->aop->size;
15929 /* Unsigned or not an integral type - fill with zeros */
15930 if (IS_BOOL (righttype) || !IS_SPEC (righttype) || SPEC_USIGN (righttype) || right->aop->type == AOP_CRY)
15932 genMove_o (result->aop, 0, right->aop, 0, right->aop->size, !surviving_a, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic), true);
15933 surviving_a |= (result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < right->aop->size);
15934 bool hl_dead = isPairDead (PAIR_HL, ic) && (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= right->aop->size) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= right->aop->size);
15935 bool de_dead = isPairDead (PAIR_DE, ic) && (result->aop->regs[E_IDX] < 0 || result->aop->regs[E_IDX] >= right->aop->size) && (result->aop->regs[D_IDX] < 0 || result->aop->regs[D_IDX] >= right->aop->size);
15936 bool iy_dead = isPairDead (PAIR_DE, ic) && (result->aop->regs[IYL_IDX] < 0 || result->aop->regs[IYL_IDX] >= right->aop->size) && (result->aop->regs[IYH_IDX] < 0 || result->aop->regs[IYH_IDX] >= right->aop->size);
15937 genMove_o (result->aop, right->aop->size, ASMOP_ZERO, 0, size, !surviving_a, hl_dead, de_dead, iy_dead, true);
15939 else
15941 bool maskedtopbyte = IS_BITINT (resulttype) && (SPEC_BITINTWIDTH (resulttype) % 8) && SPEC_USIGN (resulttype);
15942 genMove_o (result->aop, 0, right->aop, 0, right->aop->size - 1, !surviving_a, isPairDead (PAIR_HL, ic), isPairDead (PAIR_DE, ic), isPairDead (PAIR_IY, ic), true);
15943 bool de_dead = isPairDead (PAIR_DE, ic) && (result->aop->regs[E_IDX] < 0 || result->aop->regs[E_IDX] >= right->aop->size) && (result->aop->regs[D_IDX] < 0 || result->aop->regs[D_IDX] >= right->aop->size);
15944 bool iy_dead = isPairDead (PAIR_DE, ic) && (result->aop->regs[IYL_IDX] < 0 || result->aop->regs[IYL_IDX] >= right->aop->size) && (result->aop->regs[IYH_IDX] < 0 || result->aop->regs[IYH_IDX] >= right->aop->size);
15945 bool hl_dead = isPairDead (PAIR_HL, ic) && (result->aop->regs[L_IDX] < 0 || result->aop->regs[L_IDX] >= right->aop->size) && (result->aop->regs[H_IDX] < 0 || result->aop->regs[H_IDX] >= right->aop->size);
15946 if (result->aop->type == AOP_REG && right->aop->type == AOP_REG && // Overwritten last byte of right operand
15947 result->aop->regs[right->aop->aopu.aop_reg[right->aop->size - 1]->rIdx] >= 0 && result->aop->regs[right->aop->aopu.aop_reg[right->aop->size - 1]->rIdx] < right->aop->size - 1)
15948 UNIMPLEMENTED;
15949 int offset = right->aop->size - 1;
15950 surviving_a |= (result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < offset);
15951 if (surviving_a && !pushed_a)
15952 _push (PAIR_AF), pushed_a = true;
15954 genMove_o (ASMOP_A, 0, right->aop, offset, 1, true, hl_dead, de_dead, iy_dead, true);
15955 if (right->aop->type != AOP_REG || result->aop->type != AOP_REG || right->aop->aopu.aop_reg[offset] != result->aop->aopu.aop_reg[offset])
15956 cheapMove (result->aop, offset, ASMOP_A, 0, true);
15957 offset++;
15959 surviving_a |= (result->aop->regs[A_IDX] >= 0 && result->aop->regs[A_IDX] < offset);
15960 if (surviving_a && !pushed_a)
15961 _push (PAIR_AF), pushed_a = true;
15963 /* we need to extend the sign */
15964 emit3 (A_RLCA, 0, 0);
15966 if (!IS_SM83 && !maskedtopbyte && isPairDead (PAIR_HL, ic) && size == 2 && /* writing AOP_HL is so cheap, it is not worth the 2-byte sbc hl, hl here */
15967 (aopInReg (result->aop, offset, HL_IDX) || result->aop->type == AOP_IY || (IS_RAB || IS_TLCS90 || IS_EZ80_Z80) && result->aop->type == AOP_STK))
15969 emit2 ("sbc hl, hl");
15970 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
15971 spillPair (PAIR_HL);
15972 genMove_o (result->aop, offset, ASMOP_HL, 0, 2, true, true, isPairDead (PAIR_DE, ic), true, false);
15974 else
15976 emit3 (A_SBC, ASMOP_A, ASMOP_A);
15977 while (size--)
15979 if (!size && maskedtopbyte) // For casts from signed integers to wider unsigned _BitInt
15981 emit2 ("and a, #0x%02x", topbytemask);
15982 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
15984 cheapMove (result->aop, offset++, ASMOP_A, 0, true);
15989 release:
15990 if (pushed_a)
15991 _pop (PAIR_AF);
15992 freeAsmop (right, NULL);
15993 freeAsmop (result, NULL);
15996 /*-----------------------------------------------------------------*/
15997 /* genReceive - generate code for a receive iCode */
15998 /*-----------------------------------------------------------------*/
15999 static void
16000 genReceive (const iCode *ic)
16002 operand *result = IC_RESULT (ic);
16003 aopOp (result, ic, true, false);
16005 wassert (currFunc && ic->argreg);
16007 bool dead_regs[IYH_IDX + 1];
16009 for (int i = 0; i <= IYH_IDX; i++)
16010 dead_regs[i] = isRegDead (i, ic);
16012 for(iCode *nic = ic->next; nic && nic->op == RECEIVE; nic = nic->next)
16014 asmop *narg = aopArg (currFunc->type, nic->argreg);
16015 wassert (narg);
16016 for (int i = 0; i < narg->size; i++)
16017 dead_regs[narg->aopu.aop_reg[i]->rIdx] = false;
16020 if (result->aop->type == AOP_REG)
16021 for (int i = 0; i < result->aop->size; i++)
16022 if (!dead_regs[result->aop->aopu.aop_reg[i]->rIdx])
16023 UNIMPLEMENTED;
16025 genMove (result->aop, aopArg (currFunc->type, ic->argreg), dead_regs[A_IDX], dead_regs[L_IDX] && dead_regs[H_IDX], dead_regs[E_IDX] && dead_regs[D_IDX], true);
16027 freeAsmop (IC_RESULT (ic), NULL);
16030 /*-----------------------------------------------------------------*/
16031 /* genDummyRead - generate code for dummy read of volatiles */
16032 /*-----------------------------------------------------------------*/
16033 static void
16034 genDummyRead (const iCode * ic)
16036 operand *op;
16037 int size, offset;
16039 op = IC_RIGHT (ic);
16040 if (op && IS_SYMOP (op))
16042 aopOp (op, ic, FALSE, FALSE);
16044 /* general case */
16045 size = op->aop->size;
16046 offset = 0;
16048 while (size--)
16050 _moveA3 (op->aop, offset);
16051 offset++;
16054 freeAsmop (op, NULL);
16057 op = IC_LEFT (ic);
16058 if (op && IS_SYMOP (op))
16060 aopOp (op, ic, FALSE, FALSE);
16062 /* general case */
16063 size = op->aop->size;
16064 offset = 0;
16066 while (size--)
16068 _moveA3 (op->aop, offset);
16069 offset++;
16072 freeAsmop (op, NULL);
16076 /*-----------------------------------------------------------------*/
16077 /* genCritical - generate code for start of a critical sequence */
16078 /*-----------------------------------------------------------------*/
16079 static void
16080 genCritical (const iCode * ic)
16082 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
16084 if (IS_SM83 || IS_RAB || IS_TLCS90)
16086 emit2 ("!di");
16087 regalloc_dry_run_cost += 1;
16089 else if (IC_RESULT (ic))
16091 aopOp (IC_RESULT (ic), ic, true, false);
16092 cheapMove (IC_RESULT (ic)->aop, 0, ASMOP_ZERO, 0, true);
16093 if (!regalloc_dry_run)
16095 if (z80_opts.nmosZ80)
16097 emit2 ("call ___sdcc_critical_enter");
16099 else
16101 //get interrupt enable flag IFF2 into P/O
16102 emit2 ("ld a,i");
16103 //disable interrupt
16104 emit2 ("!di");
16106 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2=0
16107 emit2 ("jp PO, !tlabel", labelKey2num (tlbl->key));
16109 regalloc_dry_run_cost += 5;
16110 cheapMove (IC_RESULT (ic)->aop, 0, ASMOP_ONE, 0, true);
16111 if (!regalloc_dry_run)
16113 emit2 ("!tlabeldef", labelKey2num ((tlbl->key)));
16114 genLine.lineCurr->isLabel = 1;
16116 freeAsmop (IC_RESULT (ic), NULL);
16118 else
16120 if (z80_opts.nmosZ80)
16121 emit2 ("call ___sdcc_critical_enter");
16122 else
16124 //get interrupt enable flag IFF2 into P/O
16125 emit2 ("ld a,i");
16126 //disable interrupt
16127 emit2 ("!di");
16129 regalloc_dry_run_cost += 3;
16130 //save P/O flag
16131 if (!regalloc_dry_run) // _push unbalances _G.stack.pushed.
16132 _push (PAIR_AF);
16133 else
16134 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
16138 /*-----------------------------------------------------------------*/
16139 /* genEndCritical - generate code for end of a critical sequence */
16140 /*-----------------------------------------------------------------*/
16141 static void
16142 genEndCritical (const iCode * ic)
16144 symbol *tlbl = regalloc_dry_run ? 0 : newiTempLabel (0);
16146 if (IS_SM83 || IS_TLCS90 || IS_RAB)
16148 emit2 ("!ei");
16149 cost2 (1, 4, 3, 0, 4, 2, 1, 1);
16151 else if (IC_RIGHT (ic))
16153 aopOp (IC_RIGHT (ic), ic, FALSE, TRUE);
16154 _toBoolean (IC_RIGHT (ic), TRUE);
16156 if (!regalloc_dry_run)
16158 //don't enable interrupts if they were off before
16159 emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
16160 emit2 ("!ei");
16161 emitLabelSpill (tlbl);
16163 regalloc_dry_run_cost += 4;
16164 freeAsmop (IC_RIGHT (ic), NULL);
16166 else
16168 //restore P/O flag
16169 if (!regalloc_dry_run) // _pop unbalances _G.stack.pushed.
16170 _pop (PAIR_AF);
16171 else
16172 regalloc_dry_run_cost++;
16173 //parity odd <==> P/O=0 <==> interrupt enable flag IFF2 was 0 <==>
16174 //don't enable interrupts as they were off before
16175 if (!regalloc_dry_run)
16177 emit2 ("jp PO, !tlabel", labelKey2num (tlbl->key));
16178 emit2 ("!ei");
16179 emit2 ("!tlabeldef", labelKey2num ((tlbl->key)));
16180 genLine.lineCurr->isLabel = 1;
16182 regalloc_dry_run_cost += 4;
16186 enum
16188 /** Maximum number of bytes to emit per line. */
16189 DBEMIT_MAX_RUN = 8
16192 /** Context for the byte output chunker. */
16193 typedef struct
16195 unsigned char buffer[DBEMIT_MAX_RUN];
16196 int pos;
16197 } DBEMITCTX;
16200 /** Flushes a byte chunker by writing out all in the buffer and
16201 reseting.
16203 static void
16204 _dbFlush (DBEMITCTX * self)
16206 char line[256];
16208 if (self->pos > 0)
16210 int i;
16211 sprintf (line, ".db !immed%d", self->buffer[0]);
16213 for (i = 1; i < self->pos; i++)
16215 sprintf (line + strlen (line), ", !immed%d", self->buffer[i]);
16217 emit2 (line);
16219 self->pos = 0;
16222 /** Write out another byte, buffering until a decent line is
16223 generated.
16225 static void
16226 _dbEmit (DBEMITCTX * self, int c)
16228 if (self->pos == DBEMIT_MAX_RUN)
16230 _dbFlush (self);
16232 self->buffer[self->pos++] = c;
16235 /** Context for a simple run length encoder. */
16236 typedef struct
16238 unsigned last;
16239 unsigned char buffer[128];
16240 int pos;
16241 /** runLen may be equivalent to pos. */
16242 int runLen;
16243 } RLECTX;
16245 enum
16247 RLE_CHANGE_COST = 4,
16248 RLE_MAX_BLOCK = 127
16251 /** Flush the buffer of a run length encoder by writing out the run or
16252 data that it currently contains.
16254 static void
16255 _rleCommit (RLECTX * self)
16257 int i;
16258 if (self->pos != 0)
16260 DBEMITCTX db;
16261 memset (&db, 0, sizeof (db));
16263 emit2 (".db !immed%u", self->pos);
16265 for (i = 0; i < self->pos; i++)
16267 _dbEmit (&db, self->buffer[i]);
16269 _dbFlush (&db);
16271 /* Reset */
16272 self->pos = 0;
16275 /* Encoder design:
16276 Can get either a run or a block of random stuff.
16277 Only want to change state if a good run comes in or a run ends.
16278 Detecting run end is easy.
16279 Initial state?
16281 Say initial state is in run, len zero, last zero. Then if you get a
16282 few zeros then something else then a short run will be output.
16283 Seems OK. While in run mode, keep counting. While in random mode,
16284 keep a count of the run. If run hits margin, output all up to run,
16285 restart, enter run mode.
16288 /** Add another byte into the run length encoder, flushing as
16289 required. The run length encoder uses the Amiga IFF style, where
16290 a block is prefixed by its run length. A positive length means
16291 the next n bytes pass straight through. A negative length means
16292 that the next byte is repeated -n times. A zero terminates the
16293 chunks.
16295 static void
16296 _rleAppend (RLECTX * self, unsigned c)
16298 int i;
16300 if (c != self->last)
16302 /* The run has stopped. See if it is worthwhile writing it out
16303 as a run. Note that the random data comes in as runs of
16304 length one.
16306 if (self->runLen > RLE_CHANGE_COST)
16308 /* Yes, worthwhile. */
16309 /* Commit whatever was in the buffer. */
16310 _rleCommit (self);
16311 emit2 ("!db !immed-%u, !immedbyte", self->runLen, self->last);
16313 else
16315 /* Not worthwhile. Append to the end of the random list. */
16316 for (i = 0; i < self->runLen; i++)
16318 if (self->pos >= RLE_MAX_BLOCK)
16320 /* Commit. */
16321 _rleCommit (self);
16323 self->buffer[self->pos++] = self->last;
16326 self->runLen = 1;
16327 self->last = c;
16329 else
16331 if (self->runLen >= RLE_MAX_BLOCK)
16333 /* Commit whatever was in the buffer. */
16334 _rleCommit (self);
16336 emit2 ("!db !immed-%u, !immedbyte", self->runLen, self->last);
16337 self->runLen = 0;
16339 self->runLen++;
16343 static void
16344 _rleFlush (RLECTX * self)
16346 _rleAppend (self, -1);
16347 _rleCommit (self);
16348 self->pos = 0;
16349 self->last = 0;
16350 self->runLen = 0;
16353 /** genArrayInit - Special code for initialising an array with constant
16354 data.
16357 static void
16358 genArrayInit (iCode * ic)
16360 literalList *iLoop;
16361 int ix;
16362 int elementSize = 0, eIndex, i;
16363 sym_link *type;
16364 RLECTX rle;
16365 bool isBool = FALSE;
16366 bool isFloat = FALSE;
16367 bool saved_BC = FALSE;
16368 bool saved_DE = FALSE;
16369 bool saved_HL = FALSE;
16371 memset (&rle, 0, sizeof (rle));
16373 aopOp (IC_LEFT (ic), ic, FALSE, FALSE);
16375 if (!isPairDead (PAIR_HL, ic))
16377 _push (PAIR_HL);
16378 saved_HL = TRUE;
16380 if (!isPairDead (PAIR_DE, ic))
16382 _push (PAIR_DE);
16383 saved_DE = TRUE;
16385 if (!isPairDead (PAIR_BC, ic))
16387 _push (PAIR_BC);
16388 saved_BC = TRUE;
16391 fetchPair (PAIR_DE, IC_LEFT (ic)->aop);
16392 emit2 ("call __initrleblock");
16394 type = operandType (IC_LEFT (ic));
16396 if (type && type->next)
16398 if (IS_SPEC (type->next) || IS_PTR (type->next))
16400 elementSize = getSize (type->next);
16401 isBool = IS_BOOL (type->next);
16402 isFloat = IS_FLOAT (type->next);
16404 else if (IS_ARRAY (type->next) && type->next->next)
16406 elementSize = getSize (type->next->next);
16407 isBool = IS_BOOL (type->next->next);
16408 isFloat = IS_FLOAT (type->next->next);
16410 else
16412 printTypeChainRaw (type, NULL);
16413 wassertl (0, "Can't determine element size in genArrayInit.");
16416 else
16418 wassertl (0, "Can't determine element size in genArrayInit.");
16421 wassertl ((elementSize > 0) && (elementSize <= 8), "Illegal element size in genArrayInit.");
16423 iLoop = IC_ARRAYILIST (ic);
16425 /* Feed all the bytes into the run length encoder which will handle
16426 the actual output.
16427 This works well for mixed char data, and for random int and long
16428 data.
16430 while (iLoop)
16432 ix = iLoop->count;
16434 for (i = 0; i < ix; i++)
16436 union
16438 unsigned char c[sizeof(unsigned long long)];
16439 float f;
16440 unsigned long long ull;
16442 buf;
16443 if (isFloat)
16445 if (iLoop->isFloat)
16446 buf.f = iLoop->value.f64;
16447 else
16448 buf.f = iLoop->value.ull;
16450 else
16452 if (iLoop->isFloat)
16453 buf.ull = (isBool) ? !!iLoop->value.f64 : (unsigned long long)iLoop->value.f64;
16454 else
16455 buf.ull = (isBool) ? !!iLoop->value.ull : iLoop->value.ull;
16458 #ifdef WORDS_BIGENDIAN
16459 for (eIndex = elementSize-1; eIndex >= 0; eIndex--)
16460 #else
16461 for (eIndex = 0; eIndex < elementSize; eIndex++)
16462 #endif
16463 _rleAppend (&rle, buf.c[eIndex]);
16466 iLoop = iLoop->next;
16469 _rleFlush (&rle);
16470 /* Mark the end of the run. */
16471 emit2 (".db !zero");
16473 spillCached ();
16475 if (saved_BC)
16476 _pop (PAIR_BC);
16478 if (saved_DE)
16479 _pop (PAIR_DE);
16481 if (saved_HL)
16482 _pop (PAIR_HL);
16484 freeAsmop (IC_LEFT (ic), NULL);
16487 static void
16488 setupForMemcpy (const iCode *ic, const operand *to, const operand *from, const operand *count)
16490 /* Both are in regs. Let regMove() do the shuffling. */
16491 if (to->aop->type == AOP_REG && from->aop->type == AOP_REG)
16493 const short larray[6] = {E_IDX, D_IDX, L_IDX, H_IDX, C_IDX, B_IDX};
16494 short oparray[6];
16495 oparray[0] = to->aop->aopu.aop_reg[0]->rIdx;
16496 oparray[1] = to->aop->aopu.aop_reg[1]->rIdx;
16497 oparray[2] = from->aop->aopu.aop_reg[0]->rIdx;
16498 oparray[3] = from->aop->aopu.aop_reg[1]->rIdx;
16499 if (count && count->aop->type == AOP_REG)
16501 oparray[4] = count->aop->aopu.aop_reg[0]->rIdx;
16502 oparray[5] = count->aop->aopu.aop_reg[1]->rIdx;
16505 regMove (larray, oparray, 4 + (count && count->aop->type == AOP_REG) * 2, false);
16507 else if (to->aop->type == AOP_REG && count && count->aop->type == AOP_REG)
16509 const short larray[4] = {E_IDX, D_IDX, C_IDX, B_IDX};
16510 short oparray[4];
16511 oparray[0] = to->aop->aopu.aop_reg[0]->rIdx;
16512 oparray[1] = to->aop->aopu.aop_reg[1]->rIdx;
16513 oparray[2] = count->aop->aopu.aop_reg[0]->rIdx;
16514 oparray[3] = count->aop->aopu.aop_reg[1]->rIdx;
16516 regMove (larray, oparray, 4 , false);
16518 genMove (ASMOP_HL, from->aop, isRegDead (A_IDX, ic), true, false, isRegDead (IY_IDX, ic));
16520 else if (from->aop->type == AOP_REG && count && count->aop->type == AOP_REG)
16522 const short larray[4] = {L_IDX, H_IDX, C_IDX, B_IDX};
16523 short oparray[4];
16524 oparray[0] = from->aop->aopu.aop_reg[0]->rIdx;
16525 oparray[1] = from->aop->aopu.aop_reg[1]->rIdx;
16526 oparray[2] = count->aop->aopu.aop_reg[0]->rIdx;
16527 oparray[3] = count->aop->aopu.aop_reg[1]->rIdx;
16529 regMove (larray, oparray, 4 , false);
16531 genMove (ASMOP_DE, to->aop, isRegDead (A_IDX, ic), false, true, isRegDead (IY_IDX, ic));
16533 else if (count && count->aop->type == AOP_REG)
16535 fetchPair (PAIR_BC, count->aop);
16536 fetchPair (PAIR_DE, to->aop);
16537 genMove (ASMOP_HL, from->aop, isRegDead (A_IDX, ic), true, false, isRegDead (IY_IDX, ic));
16539 else
16541 /* DE is free. Write it first. */
16542 if (from->aop->type != AOP_REG || from->aop->aopu.aop_reg[0]->rIdx != E_IDX && from->aop->aopu.aop_reg[0]->rIdx != D_IDX && from->aop->aopu.aop_reg[1]->rIdx != E_IDX && from->aop->aopu.aop_reg[1]->rIdx != D_IDX)
16544 bool a_free = isRegDead (A_IDX, ic) && !aopInReg (from->aop, 0, A_IDX) && !aopInReg (from->aop, 1, A_IDX);
16545 bool iy_free = isRegDead (IY_IDX, ic) && !aopInReg (from->aop, 0, IYL_IDX) && !aopInReg (from->aop, 1, IYH_IDX) && !aopInReg (from->aop, 0, IYL_IDX) && !aopInReg (from->aop, 1, IYH_IDX);
16546 genMove (ASMOP_DE, to->aop, a_free, from->aop->regs[L_IDX] < 0 && from->aop->regs[H_IDX] < 0, true, iy_free);
16547 genMove (ASMOP_HL, from->aop, isRegDead (A_IDX, ic), true, false, isRegDead (IY_IDX, ic));
16549 /* HL is free. Write it first. */
16550 else if (to->aop->type != AOP_REG || to->aop->aopu.aop_reg[0]->rIdx != L_IDX && to->aop->aopu.aop_reg[0]->rIdx != H_IDX && to->aop->aopu.aop_reg[1]->rIdx != L_IDX && to->aop->aopu.aop_reg[1]->rIdx != H_IDX)
16552 bool a_free = isRegDead (A_IDX, ic) && !aopInReg (to->aop, 0, A_IDX) && !aopInReg (to->aop, 1, A_IDX);
16553 bool iy_free = isRegDead (IY_IDX, ic) && !aopInReg (to->aop, 0, IYL_IDX) && !aopInReg (to->aop, 1, IYH_IDX) && !aopInReg (to->aop, 0, IYL_IDX) && !aopInReg (to->aop, 1, IYH_IDX);
16554 genMove (ASMOP_HL, from->aop, a_free, true, to->aop->regs[E_IDX] < 0 && to->aop->regs[D_IDX] < 0, iy_free);
16555 genMove (ASMOP_DE, to->aop, isRegDead (A_IDX, ic), false, true, isRegDead (IY_IDX, ic));
16557 /* L is free, but H is not. */
16558 else if ((to->aop->type != AOP_REG || to->aop->aopu.aop_reg[0]->rIdx != L_IDX && to->aop->aopu.aop_reg[1]->rIdx != L_IDX) &&
16559 (from->aop->type != AOP_REG || from->aop->aopu.aop_reg[0]->rIdx != L_IDX && from->aop->aopu.aop_reg[1]->rIdx != L_IDX))
16561 cheapMove (ASMOP_L, 0, from->aop, 0, true);
16562 fetchPair (PAIR_DE, to->aop);
16563 cheapMove (ASMOP_H, 0, from->aop, 1, true);
16565 /* H is free, but L is not. */
16566 else
16568 cheapMove (ASMOP_H, 0, from->aop, 1, true);
16569 fetchPair (PAIR_DE, to->aop);
16570 cheapMove (ASMOP_L, 0, from->aop, 0, true);
16575 static void
16576 genBuiltInMemcpy (const iCode *ic, int nparams, operand **pparams)
16578 int i;
16579 operand *from, *to, *count;
16580 bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
16581 unsigned int n;
16583 for (i = 0; i < nparams; i++)
16584 aopOp (pparams[i], ic, FALSE, FALSE);
16586 wassertl (!IS_SM83, "Built-in memcpy() not available on sm83.");
16587 wassertl (nparams == 3, "Built-in memcpy() must have three parameters.");
16589 count = pparams[2];
16590 from = pparams[1];
16591 to = pparams[0];
16593 if (pparams[2]->aop->type != AOP_LIT)
16594 n = UINT_MAX;
16595 else if (!(n = (unsigned int) ulFromVal (pparams[2]->aop->aopu.aop_lit))) /* Check for zero length copy. */
16596 goto done;
16598 if (!isPairDead (PAIR_HL, ic))
16600 _push (PAIR_HL);
16601 saved_HL = TRUE;
16603 if (!isPairDead (PAIR_DE, ic))
16605 _push (PAIR_DE);
16606 saved_DE = TRUE;
16608 if (!isPairDead (PAIR_BC, ic) && n > 2)
16610 _push (PAIR_BC);
16611 saved_BC = TRUE;
16614 setupForMemcpy (ic, to, from, count);
16616 if (n == 1)
16618 emit2 ("ld a, !*hl");
16619 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
16620 emit2 ("ld !mems, a", "de");
16621 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
16623 else if (n == 2)
16625 emit2 ("ldi");
16626 cost2 (2, 16, 12, 10, 0, 14, 5, 4);
16627 emit2 ("ld a, !*hl");
16628 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
16629 emit2 ("ld !mems, a", "de");
16630 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
16631 if (!isPairDead (PAIR_BC, ic)) /* Restore bc. */
16632 emit3w (A_INC, ASMOP_BC, 0);
16634 else if (n <= 4 && IS_Z80 && optimize.codeSpeed || (IS_R2K || IS_R2KA) && n <= 5)
16636 for(unsigned int i = 0; i < n; i++)
16638 emit2 ("ldi");
16639 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16642 else
16644 symbol *tlbl = 0;
16645 bool to_from_stack = isOperandOnStack (to) && isOperandOnStack (from);
16646 if (count->aop->type != AOP_REG) // If in reg: Has been fetched early by setupForMemcpy() above.
16647 fetchPair (PAIR_BC, count->aop);
16648 if (count->aop->type != AOP_LIT)
16650 emit3 (A_LD, ASMOP_A, ASMOP_B);
16651 emit3 (A_OR, ASMOP_A, ASMOP_C);
16652 if (!regalloc_dry_run)
16654 tlbl = newiTempLabel (0);
16655 emit2 ("jp Z, !tlabel", labelKey2num (tlbl->key));
16657 cost2 (3, 10, 6, 7, 12, 10, 3, 3); // For cycle cost, assume that n is non-zero.
16659 if ((IS_R2K || IS_R2KA) && !to_from_stack && optimize.codeSpeed && n != UINT_MAX) // Work around Rabbit 2000 to Rabbit 3000 ldir wait state bug, but care for speed
16661 wassert (n > 3);
16662 if (n % 2)
16664 emit2 ("ldi");
16665 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16667 if (!regalloc_dry_run)
16669 const symbol *tlbl2 = newiTempLabel (0);
16670 emitLabel (tlbl2);
16671 emit2("ldi");
16672 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16673 emit2("ldi");
16674 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16675 emit2 ("jp LO, !tlabel", labelKey2num (tlbl2->key));
16677 regalloc_dry_run_cost += 3;
16679 else if ((IS_R2K || IS_R2KA) && !to_from_stack) // Work around Rabbit 2000 to Rabbit 3000 ldir wait state bug.
16681 if (!regalloc_dry_run)
16683 const symbol *tlbl2 = newiTempLabel (0);
16684 emitLabel (tlbl2);
16685 emit2("ldi");
16686 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16687 emit2 ("jp LO, !tlabel", labelKey2num (tlbl2->key));
16689 regalloc_dry_run_cost += 3;
16691 else
16693 emit2 ("ldir");
16694 regalloc_dry_run_cost += 2;
16696 emitLabel (tlbl);
16699 spillPair (PAIR_HL);
16701 if (saved_BC)
16702 _pop (PAIR_BC);
16703 if (saved_DE)
16704 _pop (PAIR_DE);
16705 if (saved_HL)
16706 _pop (PAIR_HL);
16708 done:
16709 freeAsmop (count, NULL);
16710 freeAsmop (to, NULL);
16711 freeAsmop (from, NULL);
16713 /* No need to assign result - would have used ordinary memcpy() call instead. */
16716 static void
16717 setupForMemset (const iCode *ic, const operand *dst, const operand *c, bool direct_c)
16719 /* Both are in regs. Let regMove() do the shuffling. */
16720 if (dst->aop->type == AOP_REG && !direct_c && c->aop->type == AOP_REG)
16722 const short larray[2] = {L_IDX, H_IDX};
16723 short oparray[2];
16724 bool early_a = c->aop->type == AOP_REG && (c->aop->aopu.aop_reg[0]->rIdx == L_IDX || c->aop->aopu.aop_reg[0]->rIdx == H_IDX);
16726 if (early_a)
16727 cheapMove (ASMOP_A, 0, c->aop, 0, true);
16729 oparray[0] = dst->aop->aopu.aop_reg[0]->rIdx;
16730 oparray[1] = dst->aop->aopu.aop_reg[1]->rIdx;
16732 regMove (larray, oparray, 2, early_a);
16734 if (!early_a)
16735 cheapMove (ASMOP_A, 0, c->aop, 0, true);
16737 else if (c->aop->type == AOP_REG && requiresHL (c->aop))
16739 cheapMove (ASMOP_A, 0, c->aop, 0, true);
16740 if (dst->aop->type == AOP_EXSTK)
16741 _push (PAIR_AF);
16742 fetchPair (PAIR_HL, dst->aop);
16743 if (dst->aop->type == AOP_EXSTK)
16744 _pop (PAIR_AF);
16746 else
16748 bool a_free = isRegDead (A_IDX, ic) && !aopInReg (c->aop, 0, A_IDX);
16749 genMove (ASMOP_HL, dst->aop, a_free, true, false, false);
16750 if (!direct_c)
16752 if (requiresHL (c->aop))
16753 _push (PAIR_HL);
16754 cheapMove (ASMOP_A, 0, c->aop, 0, true);
16755 if (requiresHL (c->aop))
16756 _pop (PAIR_HL);
16761 static void
16762 genBuiltInMemset (const iCode *ic, int nParams, operand **pparams)
16764 operand *dst, *c, *n;
16765 bool direct_c, direct_cl;
16766 bool indirect_c;
16767 bool preinc = FALSE;
16768 unsigned long sizecost_ldir, sizecost_direct, sizecost_loop;
16769 bool double_loop;
16770 unsigned size;
16771 bool live_BC = !isPairDead (PAIR_BC, ic), live_DE = !isPairDead (PAIR_DE, ic), live_HL = !isPairDead (PAIR_HL, ic), live_B = !isRegDead (B_IDX, ic);
16772 bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
16774 wassertl (nParams == 3, "Built-in memset() must have three parameters");
16776 dst = pparams[0];
16777 c = pparams[1];
16778 n = pparams[2];
16780 aopOp (c, ic, FALSE, FALSE);
16781 aopOp (dst, ic, FALSE, FALSE);
16782 aopOp (n, ic, FALSE, FALSE);
16784 wassertl (n->aop->type == AOP_LIT, "Last parameter to builtin memset() must be literal.");
16786 if(n->aop->type != AOP_LIT || !(size = ulFromVal (n->aop->aopu.aop_lit)))
16787 goto done;
16789 direct_c = (c->aop->type == AOP_LIT || c->aop->type == AOP_REG &&
16790 c->aop->aopu.aop_reg[0]->rIdx != H_IDX && c->aop->aopu.aop_reg[0]->rIdx != L_IDX &&
16791 c->aop->aopu.aop_reg[0]->rIdx != IYH_IDX && c->aop->aopu.aop_reg[0]->rIdx != IYL_IDX);
16792 direct_cl = (c->aop->type == AOP_LIT || c->aop->type == AOP_REG &&
16793 c->aop->aopu.aop_reg[0]->rIdx != H_IDX && c->aop->aopu.aop_reg[0]->rIdx != L_IDX &&
16794 c->aop->aopu.aop_reg[0]->rIdx != IYH_IDX && c->aop->aopu.aop_reg[0]->rIdx != IYL_IDX &&
16795 c->aop->aopu.aop_reg[0]->rIdx != B_IDX);
16796 indirect_c = IS_R3KA && ulFromVal (n->aop->aopu.aop_lit) > 1 && c->aop->type == AOP_IY;
16798 double_loop = (size > 255 || optimize.codeSpeed);
16800 int sizecost_ld_a_caop = aopInReg (c->aop, 0, A_IDX) ? 0 : ld_cost (ASMOP_A, 0, c->aop, 0, false);
16801 sizecost_direct = 3 + 2 * size - 1 + !direct_c * sizecost_ld_a_caop;
16802 sizecost_direct += (live_HL) * 2;
16803 sizecost_loop = 9 + double_loop * 2 + ((size % 2) && double_loop) * 2 + !direct_cl * sizecost_ld_a_caop;
16804 sizecost_loop += (live_HL + live_B) * 2;
16805 sizecost_ldir = indirect_c ? 11 : (12 + !direct_c * sizecost_ld_a_caop - (IS_R3KA && !optimize.codeSpeed));
16806 sizecost_ldir += (live_HL + live_DE + live_BC) * 2;
16808 if (sizecost_direct <= sizecost_loop && sizecost_direct < sizecost_ldir) // straight-line code.
16810 if (live_HL)
16812 _push (PAIR_HL);
16813 saved_HL = TRUE;
16816 setupForMemset (ic, dst, c, direct_c);
16818 while (size--)
16820 if (!regalloc_dry_run)
16821 emit2 ("ld !*hl, %s", aopGet (direct_c ? c->aop : ASMOP_A, 0, FALSE));
16822 cost2 (1, 7, 7, 6, 8, 6, 2, 2);
16823 if (size)
16824 emit3w (A_INC, ASMOP_HL, 0);
16827 else if (size <= 510 && sizecost_loop < sizecost_ldir) // Loop
16829 symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel (NULL);
16830 symbol *tlbl2 = regalloc_dry_run ? 0 : newiTempLabel (NULL);
16832 if (live_HL)
16834 _push (PAIR_HL);
16835 saved_HL = TRUE;
16837 if (!isRegDead (B_IDX, ic))
16839 _push (PAIR_BC);
16840 saved_BC = TRUE;
16843 setupForMemset (ic, dst, c, direct_cl);
16845 emit2 ("ld b, !immedbyte", double_loop ? (size / 2 + size % 2) : size);
16846 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
16848 if (double_loop && size % 2)
16850 if (!regalloc_dry_run)
16851 emit2 ("jr !tlabel", labelKey2num (tlbl2->key));
16852 regalloc_dry_run_cost += 2;
16855 if (!regalloc_dry_run)
16857 emitLabel (tlbl1);
16858 emit2 ("ld !*hl, %s", aopGet (direct_cl ? c->aop : ASMOP_A, 0, FALSE));
16859 emit2 ("inc hl");
16860 if (double_loop)
16862 if (size % 2)
16863 emitLabel (tlbl2);
16864 emit2 ("ld !*hl, %s", aopGet (direct_cl ? c->aop : ASMOP_A, 0, FALSE));
16865 emit2 ("inc hl");
16867 emit2 ("djnz !tlabel", labelKey2num (tlbl1->key));
16869 regalloc_dry_run_cost += (double_loop ? 6 : 4);
16871 else // Use ldir / lsidr
16873 if (live_HL)
16875 _push (PAIR_HL);
16876 saved_HL = true;
16878 if (live_DE)
16880 _push (PAIR_DE);
16881 saved_DE = true;
16883 if (live_BC)
16885 _push (PAIR_BC);
16886 saved_BC = true;
16888 if (indirect_c)
16890 fetchPair (PAIR_DE, dst->aop);
16891 pointPairToAop (PAIR_HL, c->aop, 0);
16893 else
16895 setupForMemset (ic, dst, c, direct_c);
16897 if (!regalloc_dry_run)
16898 emit2 ("ld !*hl, %s", aopGet (direct_c ? c->aop : ASMOP_A, 0, FALSE));
16899 regalloc_dry_run_cost += (direct_c && c->aop->type == AOP_LIT) ? 2 : 1;
16900 if (ulFromVal (n->aop->aopu.aop_lit) <= 1)
16901 goto done;
16903 emit3 (A_LD, ASMOP_E, ASMOP_L);
16904 emit3 (A_LD, ASMOP_D, ASMOP_H);
16905 if (!IS_R3KA || optimize.codeSpeed)
16907 emit2 ("inc de");
16908 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
16909 preinc = true;
16912 emit2 ("ld bc, !immedword", (unsigned)(size - preinc));
16913 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
16914 // The Rabbit 2000 to Rabbit 3000 (i.e. r2ka and r2ka port) have a ldir wait state bug that affects copies between different types of memory.
16915 // That is not a problem here, as we copy within an object, and thus within one memory.
16916 emit2 (IS_R3KA ? "lsidr" : "ldir");
16917 regalloc_dry_run_cost += 2;
16920 done:
16921 spillPair (PAIR_HL);
16923 freeAsmop (n, NULL);
16924 freeAsmop (c, NULL);
16925 freeAsmop (dst, NULL);
16927 if (saved_BC)
16928 _pop (PAIR_BC);
16929 if (saved_DE)
16930 _pop (PAIR_DE);
16931 if (saved_HL)
16932 _pop (PAIR_HL);
16934 /* No need to assign result - would have used ordinary memset() call instead. */
16937 static void
16938 genBuiltInStrcpy (const iCode *ic, int nParams, operand **pparams)
16940 operand *dst, *src;
16941 bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
16942 int i;
16943 bool SomethingReturned;
16945 SomethingReturned = IS_ITEMP (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->spildir) ||
16946 IS_TRUE_SYMOP (IC_RESULT (ic));
16948 wassertl (nParams == 2, "Built-in strcpy() must have two parameters.");
16949 wassertl (!IS_SM83, "Built-in strcpy() not available for sm83.");
16951 dst = pparams[0];
16952 src = pparams[1];
16954 for (i = 0; i < nParams; i++)
16955 aopOp (pparams[i], ic, FALSE, FALSE);
16957 if (!isPairDead (PAIR_HL, ic))
16959 _push (PAIR_HL);
16960 saved_HL = TRUE;
16962 if (!isPairDead (PAIR_BC, ic))
16964 _push (PAIR_BC);
16965 saved_BC = TRUE;
16967 if (!isPairDead (PAIR_DE, ic))
16969 _push (PAIR_DE);
16970 saved_DE = TRUE;
16973 setupForMemcpy (ic, dst, src, 0);
16975 emit3 (A_XOR, ASMOP_A, ASMOP_A);
16976 if (SomethingReturned)
16977 _push (PAIR_DE);
16978 if (!regalloc_dry_run)
16980 symbol *tlbl = newiTempLabel (NULL);
16981 emitLabel (tlbl);
16982 emit2 ("cp a, !*hl");
16983 emit2 ("ldi");
16984 emit2 ("jr NZ, !tlabel", labelKey2num (tlbl->key));
16986 regalloc_dry_run_cost += 5;
16988 spillPair (PAIR_HL);
16990 if (SomethingReturned)
16991 aopOp (IC_RESULT (ic), ic, true, false);
16993 if (!SomethingReturned || SomethingReturned && getPairId (IC_RESULT (ic)->aop) != PAIR_INVALID)
16995 if (SomethingReturned)
16996 _pop (getPairId (IC_RESULT (ic)->aop));
16997 if (saved_DE)
16998 _pop (PAIR_DE);
16999 if (saved_BC)
17000 _pop (PAIR_BC);
17001 if (saved_HL)
17002 _pop (PAIR_HL);
17004 else
17006 _pop (PAIR_HL);
17007 genMove (IC_RESULT (ic)->aop, ASMOP_HL, true, true, true, true);
17009 restoreRegs (0, saved_DE, saved_BC, saved_HL, IC_RESULT (ic), ic);
17012 if (SomethingReturned)
17013 freeAsmop (IC_RESULT (ic), NULL);
17014 freeAsmop (src, NULL);
17015 freeAsmop (dst, NULL);
17018 static void
17019 genBuiltInStrncpy (const iCode *ic, int nparams, operand **pparams)
17021 int i;
17022 operand *s1, *s2, *n;
17023 bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
17025 for (i = 0; i < nparams; i++)
17026 aopOp (pparams[i], ic, FALSE, FALSE);
17028 wassertl (!IS_SM83, "Built-in strncpy() not available on sm83.");
17029 wassertl (nparams == 3, "Built-in strncpy() must have three parameters.");
17030 wassertl (pparams[2]->aop->type == AOP_LIT, "Last parameter to builtin strncpy() must be literal.");
17032 s1 = pparams[0];
17033 s2 = pparams[1];
17034 n = pparams[2];
17036 if (!ulFromVal (n->aop->aopu.aop_lit))
17037 goto done;
17039 if (!isPairDead (PAIR_HL, ic))
17041 _push (PAIR_HL);
17042 saved_HL = TRUE;
17044 if (!isPairDead (PAIR_BC, ic))
17046 _push (PAIR_BC);
17047 saved_BC = TRUE;
17049 if (!isPairDead (PAIR_DE, ic))
17051 _push (PAIR_DE);
17052 saved_DE = TRUE;
17055 setupForMemcpy (ic, s1, s2, 0);
17057 fetchPair (PAIR_BC, n->aop);
17059 emit3 (A_XOR, ASMOP_A, ASMOP_A);
17060 if (!regalloc_dry_run)
17062 symbol *tlbl1 = newiTempLabel (0);
17063 symbol *tlbl2 = newiTempLabel (0);
17064 symbol *tlbl3 = newiTempLabel (0);
17065 emitLabel (tlbl2);
17066 emit2 ("cp a,!*hl");
17067 emit2 ("ldi");
17068 emit2 (IS_RAB ? "jp LZ, !tlabel" : "jp PO, !tlabel", labelKey2num (tlbl1->key));
17069 emit2 ("jr NZ, !tlabel", labelKey2num (tlbl2->key));
17070 emitLabel (tlbl3);
17071 emit2 ("dec hl");
17072 emit2 ("ldi");
17073 emit2 (IS_RAB ? "jp LO, !tlabel" : "jp PE, !tlabel", labelKey2num (tlbl3->key));
17074 emitLabel (tlbl1);
17076 regalloc_dry_run_cost += 14;
17078 spillPair (PAIR_HL);
17080 restoreRegs (0, saved_DE, saved_BC, saved_HL, 0, ic);
17082 done:
17083 freeAsmop (n, NULL);
17084 freeAsmop (s2, NULL);
17085 freeAsmop (s1, NULL);
17088 static void
17089 genBuiltInStrchr (const iCode *ic, int nParams, operand **pparams)
17091 operand *s, *c;
17092 bool saved_BC = FALSE, saved_DE = FALSE, saved_HL = FALSE;
17093 int i;
17094 bool SomethingReturned;
17095 PAIR_ID pair;
17096 bool direct_c;
17097 asmop *aop_c;
17098 symbol *tlbl1 = regalloc_dry_run ? 0 : newiTempLabel(0);
17099 symbol *tlbl2 = regalloc_dry_run ? 0 : newiTempLabel(0);
17101 SomethingReturned = IS_ITEMP (IC_RESULT (ic)) && (OP_SYMBOL (IC_RESULT (ic))->nRegs || OP_SYMBOL (IC_RESULT (ic))->spildir) ||
17102 IS_TRUE_SYMOP (IC_RESULT (ic));
17104 wassertl (nParams == 2, "Built-in strchr() must have two parameters.");
17106 s = pparams[0];
17107 c = pparams[1];
17109 for (i = 0; i < nParams; i++)
17110 aopOp (pparams[i], ic, FALSE, FALSE);
17112 if (SomethingReturned)
17113 aopOp (IC_RESULT (ic), ic, true, false);
17115 if (getPairId (s->aop) != PAIR_INVALID && getPairId (s->aop) != PAIR_IY)
17116 pair = getPairId (s->aop);
17117 else if (SomethingReturned && getPairId (IC_RESULT (ic)->aop) != PAIR_INVALID && getPairId (IC_RESULT (ic)->aop) != PAIR_IY)
17118 pair = getPairId (IC_RESULT (ic)->aop);
17119 else
17120 pair = PAIR_HL;
17122 if (c->aop->type == AOP_REG && c->aop->aopu.aop_reg[0]->rIdx != IYL_IDX && c->aop->aopu.aop_reg[0]->rIdx != IYH_IDX &&
17123 c->aop->aopu.aop_reg[0]->rIdx != A_IDX &&
17124 !(pair == PAIR_HL && (c->aop->aopu.aop_reg[0]->rIdx == L_IDX || c->aop->aopu.aop_reg[0]->rIdx == H_IDX)) &&
17125 !(pair == PAIR_DE && (c->aop->aopu.aop_reg[0]->rIdx == E_IDX || c->aop->aopu.aop_reg[0]->rIdx == D_IDX)) &&
17126 !(pair == PAIR_BC && (c->aop->aopu.aop_reg[0]->rIdx == B_IDX || c->aop->aopu.aop_reg[0]->rIdx == C_IDX)))
17127 direct_c = true;
17128 else if (c->aop->type == AOP_LIT && optimize.codeSize)
17129 direct_c = true;
17130 else
17131 direct_c = false;
17133 aop_c = direct_c ? c->aop : (pair == PAIR_DE ? ASMOP_H : ASMOP_D);
17135 if ((pair == PAIR_HL || pair == PAIR_DE && !direct_c) && !isPairDead (PAIR_HL, ic))
17137 _push (PAIR_HL);
17138 saved_HL = TRUE;
17140 if (pair == PAIR_BC && !isPairDead (PAIR_BC, ic))
17142 _push (PAIR_BC);
17143 saved_BC = TRUE;
17145 if ((pair == PAIR_DE || !direct_c) && !isPairDead (PAIR_DE, ic))
17147 _push (PAIR_DE);
17148 saved_DE = TRUE;
17151 if (!direct_c)
17152 cheapMove (aop_c, 0, c->aop, 0, true);
17153 fetchPair (pair, s->aop);
17155 if (!isRegDead (A_IDX, ic))
17156 UNIMPLEMENTED;
17158 if (!regalloc_dry_run)
17159 emitLabel (tlbl2);
17160 emit2 ("ld a, !mems", _pairs[pair].name);
17161 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
17162 emit3 (A_CP, ASMOP_A, aop_c);
17163 if (!regalloc_dry_run)
17164 emit2 ("jp Z, !tlabel", labelKey2num (tlbl1->key));
17165 emit2 ("or a, a");
17166 emit2 ("inc %s", _pairs[pair].name);
17167 if (!regalloc_dry_run)
17168 emit2 ("jr NZ, !tlabel", labelKey2num (tlbl2->key));
17169 emit2 ("ld %s, a", _pairs[pair].l);
17170 emit2 ("ld %s, a", _pairs[pair].h);
17171 regalloc_dry_run_cost += 8; // jp will most likely be optimized into jr.
17172 if (!regalloc_dry_run)
17173 emitLabel (tlbl1);
17174 if (SomethingReturned)
17175 commitPair (IC_RESULT (ic)->aop, pair, ic, FALSE);
17177 restoreRegs (0, saved_DE, saved_BC, saved_HL, SomethingReturned ? IC_RESULT (ic) : 0, ic);
17179 if (SomethingReturned)
17180 freeAsmop (IC_RESULT (ic), NULL);
17181 freeAsmop (c, NULL);
17182 freeAsmop (s, NULL);
17185 /*-----------------------------------------------------------------*/
17186 /* genBuiltIn - calls the appropriate function to generate code */
17187 /* for a built in function */
17188 /*-----------------------------------------------------------------*/
17189 static void
17190 genBuiltIn (iCode *ic)
17192 operand *bi_parms[MAX_BUILTIN_ARGS];
17193 int nbi_parms;
17194 iCode *bi_iCode;
17195 symbol *bif;
17197 /* get all the arguments for a built in function */
17198 bi_iCode = getBuiltinParms (ic, &nbi_parms, bi_parms);
17200 /* which function is it */
17201 bif = OP_SYMBOL (IC_LEFT (bi_iCode));
17203 wassertl (!ic->prev || ic->prev->op != SEND || !ic->prev->builtinSEND, "genBuiltIn() must be called on first SEND icode only.");
17205 if (!strcmp (bif->name, "__builtin_memcpy"))
17207 genBuiltInMemcpy (bi_iCode, nbi_parms, bi_parms);
17209 else if (!strcmp (bif->name, "__builtin_strcpy"))
17211 genBuiltInStrcpy (bi_iCode, nbi_parms, bi_parms);
17213 else if (!strcmp (bif->name, "__builtin_strncpy"))
17215 genBuiltInStrncpy (bi_iCode, nbi_parms, bi_parms);
17217 else if (!strcmp (bif->name, "__builtin_strchr"))
17219 genBuiltInStrchr (bi_iCode, nbi_parms, bi_parms);
17221 else if (!strcmp (bif->name, "__builtin_memset"))
17223 genBuiltInMemset (bi_iCode, nbi_parms, bi_parms);
17225 else
17227 wassertl (0, "Unknown builtin function encountered");
17231 /*-------------------------------------------------------------------------------------*/
17232 /* genZ80iCode - generate code for Z80 based controllers for a single iCode instruction*/
17233 /*-------------------------------------------------------------------------------------*/
17234 static void
17235 genZ80iCode (iCode * ic)
17237 genLine.lineElement.ic = ic;
17239 /* if the result is marked as
17240 spilt and rematerializable or code for
17241 this has already been generated then
17242 do nothing */
17243 if (resultRemat (ic))
17245 emitDebug ("; skipping iCode since result will be rematerialized");
17246 return;
17249 if (ic->generated)
17251 emitDebug ("; skipping generated iCode");
17252 return;
17255 /* depending on the operation */
17256 switch (ic->op)
17258 case '!':
17259 emitDebug ("; genNot");
17260 genNot (ic);
17261 break;
17263 case '~':
17264 emitDebug ("; genCpl");
17265 genCpl (ic);
17266 break;
17268 case UNARYMINUS:
17269 emitDebug ("; genUminus");
17270 genUminus (ic);
17271 break;
17273 case IPUSH:
17274 emitDebug ("; genIpush");
17275 genIpush (ic);
17276 break;
17278 case IPUSH_VALUE_AT_ADDRESS:
17279 emitDebug ("; genPointerPush");
17280 genPointerPush (ic);
17281 break;
17283 case CALL:
17284 case PCALL:
17285 emitDebug ("; genCall");
17286 genCall (ic);
17287 break;
17289 case FUNCTION:
17290 emitDebug ("; genFunction");
17291 genFunction (ic);
17292 break;
17294 case ENDFUNCTION:
17295 emitDebug ("; genEndFunction");
17296 genEndFunction (ic);
17297 break;
17299 case RETURN:
17300 emitDebug ("; genRet");
17301 genRet (ic);
17302 break;
17304 case LABEL:
17305 emitDebug ("; genLabel");
17306 genLabel (ic);
17307 break;
17309 case GOTO:
17310 emitDebug ("; genGoto");
17311 genGoto (ic);
17312 break;
17314 case '+':
17315 emitDebug ("; genPlus");
17316 genPlus (ic);
17317 break;
17319 case '-':
17320 emitDebug ("; genMinus");
17321 genMinus (ic, ic->next->op == IFX ? ic->next : 0);
17322 break;
17324 case '*':
17325 emitDebug ("; genMult");
17326 genMult (ic);
17327 break;
17329 case '/':
17330 emitDebug ("; genDiv");
17331 genDiv (ic);
17332 break;
17334 case '%':
17335 emitDebug ("; genMod");
17336 genMod (ic);
17337 break;
17339 case '>':
17340 emitDebug ("; genCmpGt");
17341 genCmpGt (ic, ifxForOp (IC_RESULT (ic), ic));
17342 break;
17344 case '<':
17345 emitDebug ("; genCmpLt");
17346 genCmpLt (ic, ifxForOp (IC_RESULT (ic), ic));
17347 break;
17349 case LE_OP:
17350 case GE_OP:
17351 case NE_OP:
17353 /* note these two are xlated by algebraic equivalence
17354 during parsing SDCC.y */
17355 werror (E_INTERNAL_ERROR, __FILE__, __LINE__, "got '>=' or '<=' shouldn't have come here");
17356 break;
17358 case EQ_OP:
17359 emitDebug ("; genCmpEq");
17360 genCmpEq (ic, ifxForOp (IC_RESULT (ic), ic));
17361 break;
17363 case AND_OP:
17364 emitDebug ("; genAndOp");
17365 genAndOp (ic);
17366 break;
17368 case OR_OP:
17369 emitDebug ("; genOrOp");
17370 genOrOp (ic);
17371 break;
17373 case '^':
17374 emitDebug ("; genXor");
17375 genXor (ic, ifxForOp (IC_RESULT (ic), ic));
17376 break;
17378 case '|':
17379 emitDebug ("; genOr");
17380 genOr (ic, ifxForOp (IC_RESULT (ic), ic));
17381 break;
17383 case BITWISEAND:
17384 emitDebug ("; genAnd");
17385 genAnd (ic, ifxForOp (IC_RESULT (ic), ic));
17386 break;
17388 case INLINEASM:
17389 emitDebug ("; genInline");
17390 genInline (ic);
17391 break;
17393 case GETABIT:
17394 emitDebug ("; genGetAbit");
17395 genGetAbit (ic);
17396 break;
17398 case GETBYTE:
17399 emitDebug ("; genGetByte");
17400 genGetByte (ic);
17401 break;
17403 case GETWORD:
17404 emitDebug ("; genGetWord");
17405 genGetWord (ic);
17406 break;
17408 case ROT:
17409 emitDebug ("; genRot");
17410 genRot (ic);
17411 break;
17413 case LEFT_OP:
17414 emitDebug ("; genLeftShift");
17415 genLeftShift (ic);
17416 break;
17418 case RIGHT_OP:
17419 emitDebug ("; genRightShift");
17420 genRightShift (ic);
17421 break;
17423 case GET_VALUE_AT_ADDRESS:
17424 emitDebug ("; genPointerGet");
17425 genPointerGet (ic);
17426 break;
17428 case '=':
17430 if (POINTER_SET (ic))
17432 emitDebug ("; genPointerSet");
17433 genPointerSet (ic);
17435 else
17437 emitDebug ("; genAssign");
17438 genAssign (ic);
17440 break;
17442 case IFX:
17443 emitDebug ("; genIfx");
17444 genIfx (ic, NULL);
17445 break;
17447 case ADDRESS_OF:
17448 emitDebug ("; genAddrOf");
17449 genAddrOf (ic);
17450 break;
17452 case JUMPTABLE:
17453 emitDebug ("; genJumpTab");
17454 genJumpTab (ic);
17455 break;
17457 case CAST:
17458 emitDebug ("; genCast");
17459 genCast (ic);
17460 break;
17462 case RECEIVE:
17463 emitDebug ("; genReceive");
17464 genReceive (ic);
17465 break;
17467 case SEND:
17468 if (ic->builtinSEND)
17470 emitDebug ("; genBuiltIn");
17471 genBuiltIn (ic);
17473 else
17475 emitDebug ("; genSend");
17476 genSend (ic);
17478 break;
17480 case ARRAYINIT:
17481 emitDebug ("; genArrayInit");
17482 genArrayInit (ic);
17483 break;
17485 case DUMMY_READ_VOLATILE:
17486 emitDebug ("; genDummyRead");
17487 genDummyRead (ic);
17488 break;
17490 case CRITICAL:
17491 emitDebug ("; genCritical");
17492 genCritical (ic);
17493 break;
17495 case ENDCRITICAL:
17496 emitDebug ("; genEndCritical");
17497 genEndCritical (ic);
17498 break;
17500 default:
17501 wassertl (0, "Unknown iCode");
17505 float
17506 dryZ80iCode (iCode * ic)
17508 regalloc_dry_run = true;
17509 regalloc_dry_run_cost = 0;
17510 regalloc_dry_run_cost_bytes = 0;
17511 regalloc_dry_run_cost_states = 0;
17513 initGenLineElement ();
17514 _G.omitFramePtr = should_omit_frame_ptr;
17516 genZ80iCode (ic);
17518 destroy_line_list ();
17519 freeTrace (&_G.trace.aops);
17522 int pairId;
17523 for (pairId = 0; pairId < NUM_PAIRS; pairId++)
17524 spillPair (pairId);
17527 const unsigned int state_cost_divider = 8u << (optimize.codeSize * 3 + !optimize.codeSpeed * 3);
17529 // Hack, since the legacy regalloc_dry_run_cost is still used in some places.
17530 regalloc_dry_run_cost_bytes += regalloc_dry_run_cost;
17531 regalloc_dry_run_cost_states += regalloc_dry_run_cost * 4; // Assume 4 states per byte.
17533 // Compensate for typically lower state count of some targets
17534 if (IS_RAB)
17535 regalloc_dry_run_cost_states *= 2;
17536 else if (IS_EZ80_Z80 || IS_R800)
17537 regalloc_dry_run_cost_states *= 3;
17539 return (regalloc_dry_run_cost_bytes + regalloc_dry_run_cost_states * ic->count / state_cost_divider);
17542 #ifdef DEBUG_DRY_COST
17543 static void
17544 dryZ80Code (iCode * lic)
17546 iCode *ic;
17548 for (ic = lic; ic; ic = ic->next)
17549 if (ic->op != FUNCTION && ic->op != ENDFUNCTION && ic->op != LABEL && ic->op != GOTO && ic->op != INLINEASM)
17551 printf ("; iCode %d total cost: %f ", ic->key, dryZ80iCode (ic));
17552 const unsigned int state_cost_divider = 8u << (optimize.codeSize * 3 + !optimize.codeSpeed * 3);
17553 printf ("(%f + %f * %f * 0.0001 / %u\n", (float)regalloc_dry_run_cost_bytes, regalloc_dry_run_cost_states, ic->count, state_cost_divider);
17556 #endif
17558 /*-------------------------------------------------------------------------------------*/
17559 /* genZ80Code - generate code for Z80 based controllers for a block of instructions */
17560 /*-------------------------------------------------------------------------------------*/
17561 void
17562 genZ80Code (iCode * lic)
17564 #ifdef DEBUG_DRY_COST
17565 dryZ80Code (lic);
17566 #endif
17568 iCode *ic;
17569 int cln = 0;
17570 regalloc_dry_run = false;
17572 initGenLineElement ();
17574 memset(z80_regs_used_as_parms_in_calls_from_current_function, 0, sizeof(bool) * (IYH_IDX + 1));
17575 z80_symmParm_in_calls_from_current_function = TRUE;
17576 memset(z80_regs_preserved_in_calls_from_current_function, 0, sizeof(bool) * (IYH_IDX + 1));
17578 /* if debug information required */
17579 if (options.debug && currFunc)
17581 debugFile->writeFunction (currFunc, lic);
17584 /* Generate Code for all instructions */
17585 for (ic = lic; ic; ic = ic->next)
17587 if (ic->lineno && cln != ic->lineno)
17589 if (options.debug)
17590 debugFile->writeCLine (ic);
17591 if (!options.noCcodeInAsm)
17592 emit2 (";%s:%d: %s", ic->filename, ic->lineno, printCLine (ic->filename, ic->lineno));
17593 cln = ic->lineno;
17595 if (options.iCodeInAsm)
17597 const char *iLine = printILine (ic);
17598 emit2 (";ic:%d: %s", ic->key, iLine);
17599 dbuf_free (iLine);
17601 //regalloc_dry_run_cost = 0;
17602 regalloc_dry_run_cost_bytes = 0;
17603 regalloc_dry_run_cost_states = 0;
17604 genZ80iCode (ic);
17606 #if 0 // Helpful to debug "Unbalanced stack" errors.
17607 printf("After ic %d (op %d): _G.stack.pushed: %d\n", ic->key, ic->op, _G.stack.pushed);
17608 #endif
17610 #ifdef DEBUG_DRY_COST
17611 emit2 ("; iCode %d (count %f) total costs: %u %lu %f\n", ic->key, ic->count, regalloc_dry_run_cost, regalloc_dry_run_cost_bytes, regalloc_dry_run_cost_states);
17612 #endif
17615 /* now we are ready to call the
17616 peep hole optimizer */
17617 if (!options.nopeep)
17618 peepHole (&genLine.lineHead);
17620 /* This is unfortunate */
17621 /* now do the actual printing */
17623 struct dbuf_s *buf = codeOutBuf;
17624 if (isInHome () && codeOutBuf == &code->oBuf)
17625 codeOutBuf = &home->oBuf;
17626 printLine (genLine.lineHead, codeOutBuf);
17627 if (_G.flushStatics)
17629 flushStatics ();
17630 _G.flushStatics = 0;
17632 codeOutBuf = buf;
17636 int pairId;
17637 for (pairId = 0; pairId < NUM_PAIRS; pairId++)
17638 spillPair (pairId);
17641 destroy_line_list ();
17642 freeTrace (&_G.trace.aops);
17645 // Check if what is returned by the curent function.
17646 bool
17647 z80IsReturned(const char *what)
17649 if (!strcmp(what, "iy"))
17650 return (z80IsReturned ("iyl") || z80IsReturned ("iyh"));
17652 const asmop *retaop = aopRet (currFunc->type);
17654 if (!retaop)
17655 return false;
17656 for (int i = 0; i < retaop->size; i++)
17657 if (!strcmp(retaop->aopu.aop_reg[i]->name, what))
17658 return true;
17659 return false;
17662 // Check if what is part of the ith argument (counting from 1) to a function of type ftype.
17663 // If what is 0, just check if the ith argument is in registers.
17664 bool
17665 z80IsRegArg(struct sym_link *ftype, int i, const char *what)
17667 if (what && !strcmp(what, "iy"))
17668 return (z80IsRegArg (ftype, i, "iyl") || z80IsRegArg (ftype, i, "iyh"));
17670 const asmop *argaop = aopArg (ftype, i);
17672 if (!argaop)
17673 return false;
17675 if (!what)
17676 return true;
17678 for (int i = 0; i < argaop->size; i++)
17679 if (!strcmp(argaop->aopu.aop_reg[i]->name, what))
17680 return true;
17682 return false;
17685 bool
17686 z80IsParmInCall(sym_link *ftype, const char *what)
17688 const value *args;
17689 int i;
17691 for (i = 1, args = FUNC_ARGS (ftype); args; args = args->next, i++)
17692 if (z80IsRegArg(ftype, i, what))
17693 return true;
17694 return false;