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
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 -------------------------------------------------------------------------*/
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 */
40 /* Set to enable debugging trace statements in the output assembly code. */
44 #define UNIMPLEMENTED do {wassertl (regalloc_dry_run, "Unimplemented"); cost (4000, 4000.0f);} while(0)
48 extern struct dbuf_s
*codeOutBuf
;
56 /** Enum covering all the possible register 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
142 static const char *asminstnames
[] =
174 /** Code generator persistent data.
178 /** Used to optimise setting up of a pair by remembering what it
179 contains and adjusting instead of reloading where possible.
184 const char *base
; // For addresses
185 unsigned int value
; // For AOP_LIT
211 const char *lastFunctionName
;
212 iCode
*current_iCode
;
219 /** TRUE if the registers have already been saved. */
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.
266 z80_init_reg_asmop(asmop
*aop
, const signed char *regidx
)
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
;
279 aop
->valinfo
.anything
= true;
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");
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");
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");
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
;
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
;
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
;
342 regalloc_dry_run_cost_states
+= z180_states
* regalloc_dry_run_state_scale
;
344 regalloc_dry_run_cost_states
+= r2k_clocks
* regalloc_dry_run_state_scale
;
346 regalloc_dry_run_cost_states
+= sm83_cycles
* regalloc_dry_run_state_scale
;
348 regalloc_dry_run_cost_states
+= tlcs90_states
* regalloc_dry_run_state_scale
;
350 regalloc_dry_run_cost_states
+= ez80_z80_cycles
* regalloc_dry_run_state_scale
;
352 regalloc_dry_run_cost_states
+= r800_cycles
* regalloc_dry_run_state_scale
;
357 /*-----------------------------------------------------------------*/
358 /* isRegIdxPair - true, if specified index is register pair, */
359 /* rIdx changed to index of lower register */
360 /*-----------------------------------------------------------------*/
362 isRegIdxPair (short *rIdx
)
384 /*-----------------------------------------------------------------*/
385 /* aopRegOffset - return register offset in the asmop */
386 /*-----------------------------------------------------------------*/
388 aopRegOffset (const asmop
*aop
, short rIdx
)
390 if (rIdx
< 0 || aop
->type
!= AOP_REG
)
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 /*-----------------------------------------------------------------*/
404 aopRegUsed (const asmop
*aop
, short rIdx
)
406 if (aop
->type
!= AOP_REG
)
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 /*-----------------------------------------------------------------*/
419 aopRegUsedRange (const asmop
*aop
, short rIdx
, int minPos
, int maxPos
)
421 if (aop
->type
!= AOP_REG
)
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 /*-----------------------------------------------------------------*/
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 /*-----------------------------------------------------------------*/
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;
455 if (aop
->size
<= offset
&& !b
&& aop
->type
!= AOP_LIT
)
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
)
464 if (aop
->type
!= AOP_LIT
)
467 if (byteOfVal (aop
->aopu
.aop_lit
, offset
) != b
)
474 /*-----------------------------------------------------------------*/
475 /* aopIsLitBit - asmop from offset is val. */
476 /* False negatives are possible. */
477 /*-----------------------------------------------------------------*/
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
)
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 /*-----------------------------------------------------------------*/
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;
506 if (aop
->size
<= offset
&& b
)
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
))
517 if (!offset
&& aop
->valinfo
.min
> 0 && aop
->valinfo
.max
<= 255 &&
518 (aop
->valinfo
.min
> b
|| aop
->valinfo
.min
< b
))
522 if (aop
->type
!= AOP_LIT
)
525 if (byteOfVal (aop
->aopu
.aop_lit
, offset
) != b
)
532 /*-----------------------------------------------------------------*/
533 /* aopInReg - asmop from offset in the register */
534 /*-----------------------------------------------------------------*/
536 aopInReg (const asmop
*aop
, int offset
, short rIdx
)
538 if (offset
>= aop
->size
|| offset
< 0)
541 return aopRegOffset (aop
, rIdx
) == offset
;
544 /*-----------------------------------------------------------------*/
545 /* aopOnStack - asmop from offset on stack in consecutive memory */
546 /*-----------------------------------------------------------------*/
548 aopOnStack (const asmop
*aop
, int offset
, int size
)
550 if (!(aop
->type
== AOP_STK
|| aop
->type
== AOP_EXSTK
))
553 if (offset
+ size
> aop
->size
)
560 fpOffset (int aop_stk
)
562 return aop_stk
+ (aop_stk
> 0 ? _G
.stack
.param_offset
: 0);
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. */
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)
593 bitVectUnSetBit (uses
, bitVectFirstBit (uses
));
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);
608 _getTempPairId (void)
621 _getTempPairName (void)
623 return _pairs
[_getTempPairId ()].name
;
627 isPairInUse (PAIR_ID id
, const iCode
* ic
)
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
);
639 wassertl (0, "Only implemented for DE and BC");
645 isPairDead (PAIR_ID id
, const iCode
* ic
)
650 return isRegDead (D_IDX
, ic
) && isRegDead (E_IDX
, ic
);
652 return isRegDead (B_IDX
, ic
) && isRegDead (C_IDX
, ic
);
654 return isRegDead (H_IDX
, ic
) && isRegDead (L_IDX
, ic
);
656 return isRegDead (IYH_IDX
, ic
) && isRegDead (IYL_IDX
, ic
);
658 wassertl (0, "Only implemented for DE, BC, HL and IY");
664 getDeadPairId (const iCode
*ic
)
666 if (isPairDead (PAIR_BC
, ic
))
670 else if (!IS_SM83
&& isPairDead (PAIR_DE
, ic
))
681 getFreePairId (const iCode
*ic
)
683 if (!isPairInUse (PAIR_BC
, ic
))
687 else if (!IS_SM83
&& !isPairInUse (PAIR_DE
, ic
))
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
720 _vemit2 (const char *szFormat
, va_list ap
)
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
);
733 /* Decompose multiline macros */
734 while ((nextp
= strchr (p
, '\n')))
747 emitDebug (const char *szFormat
, ...)
749 if (!DISABLE_DEBUG
&& !regalloc_dry_run
&& options
.verboseAsm
)
753 va_start (ap
, szFormat
);
754 _vemit2 (szFormat
, ap
);
760 emit2 (const char *szFormat
, ...)
762 if (!regalloc_dry_run
)
766 va_start (ap
, szFormat
);
767 _vemit2 (szFormat
, ap
);
773 getPartPairId (const asmop
*aop
, int offset
)
775 if (aop
->size
<= offset
+ 1 || offset
< 0)
778 if (aop
->type
!= AOP_REG
)
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
))
785 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== E_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== D_IDX
))
787 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== L_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== H_IDX
))
789 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== IYL_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== IYH_IDX
))
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
))
808 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== E_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== D_IDX
))
812 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== L_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== H_IDX
))
816 if ((aop
->aopu
.aop_reg
[offset
]->rIdx
== IYL_IDX
) && (aop
->aopu
.aop_reg
[offset
+ 1]->rIdx
== IYH_IDX
))
826 getPairId (const asmop
*aop
)
830 return (getPairId_o (aop
, 0));
834 /*-----------------------------------------------------------------*/
835 /* z80_emitDebuggerSymbol - associate the current code location */
836 /* with a debugger symbol */
837 /*-----------------------------------------------------------------*/
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.
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
;
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
)
882 cost2 (2, 8, 0, 0, 0, 0, 2, 2);
886 if (IS_TLCS90
&& (op1
->aopu
.aop_reg
[offset1
]->rIdx
== A_IDX
|| op1type
== AOP_DUMMY
))
895 cost2 (1 + IS_TLCS90
, 4, 4, 2, 4, 4, 1, 1);
896 return (1 + IS_TLCS90
);
900 if (op1
->aopu
.aop_reg
[offset1
]->rIdx
== IYL_IDX
|| op1
->aopu
.aop_reg
[offset1
]->rIdx
== IYH_IDX
)
903 cost2 (3, 11, 0, 0, 0, 0, 2, 3); // ld ir, #n
909 cost2 (2, 7, 6, 4, 8, 4, 2, 2); // ld r, #n
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);
922 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld r, d(ix)
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)
931 case AOP_EXSTK
: // Approximation. Don't really know if this is really exstk at this point, anyway.
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)
940 if (op2
->aopu
.aop_pairId
== PAIR_HL
)
943 cost2 (1, 7, 6, 5, 8, 6, 2, 2); // ld r, (hl)
946 if (op2
->aopu
.aop_pairId
== PAIR_IY
|| op2
->aopu
.aop_pairId
== PAIR_IX
)
949 cost2 (3, 19, 14, 9, 0, 10, 4, 5); // ld r, d(ix)
952 if (op2
->aopu
.aop_pairId
== PAIR_BC
|| op2
->aopu
.aop_pairId
== PAIR_DE
)
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);
963 fprintf (stderr
, "ld_cost op1: AOP_REG, op2: %d\n", (int) (op2type
));
968 cost2 (2, 11, 10, 0, 0, 0, 3, 3); // out (n), a
969 if (aopInReg (op1
, 0, A_IDX
))
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, #... */
980 case AOP_SFR
: /* 2 from in a, (...) */
983 case AOP_HL
: /* 3 from ld hl, #... */
989 printf ("ld_cost op1: AOP_IY, op2: %d\n", (int) (op2type
));
998 cost2 (4, 19, 15, 11, 0, 12, 5, 5); // ld d(ix), n
1000 case AOP_SFR
: /* 2 from in a, (...) */
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
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
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
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
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
));
1036 printf ("ld_cost op1: AOP_STK, op2: %d\n", (int) (op2type
));
1041 cost2 (3, 10, 9, 6, 12, 6, 3, 3); // ld hl, #nn
1047 cost2 (1, 7, 7, 6, 8, 6, 2, 2); // ld (hl), r
1052 cost2 (2 + IS_TLCS90
, 10, 9, 7, 12, 8, 3, 3); // ld (hl), n
1053 return (5 + IS_TLCS90
);
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
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
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
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
1086 printf ("ld_cost op1: AOP_HL, op2: %d", (int) (op2type
));
1091 wassertl (0, "Trying to assign a value to a literal");
1097 if (op1
->aopu
.aop_pairId
== PAIR_HL
)
1099 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
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);
1111 if (op1
->aopu
.aop_pairId
== PAIR_HL
)
1113 cost2 (2, 10, 9, 7, 12, 8, 3, 3);
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);
1129 printf ("ld_cost op1: %d\n", (int) (op1type
));
1132 return (12); // Fallback
1136 op8_cost (const asmop
*op
, int offset
)
1141 if (op
->aopu
.aop_reg
[offset
]->rIdx
== IYL_IDX
|| op
->aopu
.aop_reg
[offset
]->rIdx
== IYH_IDX
) // eZ80
1143 wassert (HAS_IYL_INST
);
1148 cost2 (1, 4, 4, 2, 4, 4, 1, 1);
1152 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
1157 cost2 (3, 19, 15, 9, 0, 10, 4, 5);
1160 cost (1, 8); // add hl, sp
1162 cost2 (3 + 1, 10 + 7, 9 + 6, 6 + 5, 12 + 8, 6 + 6, 3 + 2, 3 + 2);
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);
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);
1177 printf ("op8_cost op: %d\n", (int) (op
->type
));
1183 incdec_cost (const asmop
*op
, int offset
)
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
);
1195 cost2 (1, 4, 4, 2, 4, 2, 2, 1);
1200 cost2 (3, 23, 18, 12, 0, 12, 6, 7);
1203 cost (1, 8); // add hl, sp
1205 cost2 (3 + 1, 10 + 11, 9 + 10, 6 + 8, 12 + 12, 6 + 8, 3 + 5, 3 + 4);
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);
1212 if (op
->aopu
.aop_pairId
== PAIR_HL
)
1214 cost2 (1, 11, 10, 8, 12, 8, 5, 4);
1217 if (op
->aopu
.aop_pairId
== PAIR_IY
|| op
->aopu
.aop_pairId
== PAIR_IX
)
1219 cost2 (3, 23, 18, 12, 0, 12, 6, 7);
1223 printf ("op8_cost op: %d\n", (int) (op
->type
));
1229 bit8_cost (const asmop
*op
)
1235 cost2 (2, 8, 7, 4, 8, 4, 2, 2);
1240 cost2 (4, 23, 19, 13, 0, 12, 7, 7);
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);
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);
1252 printf ("bit8_cost op: %d\n", (int) (op
->type
));
1258 emit3Cost (enum asminst inst
, const asmop
*op1
, int offset1
, const asmop
*op2
, int offset2
)
1260 if (op2
&& offset2
>= op2
->size
)
1270 cost2 (1, 4, 3, 2, 4, 2, 1, 1);
1273 cost2 (2, 8, 6, 4, 0, 2, 2, 2);
1277 cost2 (2, 18, 16, 0, 0, 12, 5, 5);
1280 ld_cost (op1
, offset1
, op2
, offset2
, true);
1290 op8_cost (op2
, offset2
);
1294 incdec_cost (op1
, offset1
);
1307 wassertl (0, "Tried get cost for unknown instruction");
1312 emit3wCost (enum asminst inst
, const asmop
*op1
, int offset1
, const asmop
*op2
, int offset2
)
1314 if (op2
&& offset2
>= op2
->size
)
1321 if (aopInReg (op1
, offset1
, IY_IDX
))
1322 cost2 (2 - IS_TLCS90
, 10, 7, 4, 0, 4, 2, 2);
1324 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
1327 if (aopInReg (op1
, offset1
, IY_IDX
))
1328 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
1330 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
1334 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
1337 cost2 (1, 4, 3, 2, 0, 2, 1, 1);
1340 wassertl (0, "Tried get cost for unknown instruction");
1345 emit3_o (enum asminst inst
, asmop
*op1
, int offset1
, asmop
*op2
, int offset2
)
1347 unsigned long cost
, bytecost
;
1350 emit3Cost (inst
, op1
, offset1
, op2
, offset2
);
1352 if (regalloc_dry_run
)
1355 cost
= regalloc_dry_run_cost
;
1356 bytecost
= regalloc_dry_run_cost_bytes
;
1357 statecost
= regalloc_dry_run_cost_states
;
1359 emit2 ("%s", asminstnames
[inst
]);
1361 emit2 ("%s %s", asminstnames
[inst
], aopGet (op1
, offset1
, FALSE
));
1364 char *l
= Safe_strdup (aopGet (op1
, offset1
, FALSE
));
1365 emit2 ("%s %s, %s", asminstnames
[inst
], l
, aopGet (op2
, offset2
, FALSE
));
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);
1376 emit3w_o (enum asminst inst
, asmop
*op1
, int offset1
, asmop
*op2
, int offset2
)
1378 unsigned int cost
, bytecost
;
1381 emit3wCost (inst
, op1
, offset1
, op2
, offset2
);
1383 if (regalloc_dry_run
)
1386 cost
= regalloc_dry_run_cost
;
1387 bytecost
= regalloc_dry_run_cost_bytes
;
1388 statecost
= regalloc_dry_run_cost_states
;
1390 emit2 ("%s", asminstnames
[inst
]);
1392 emit2 ("%s %s", asminstnames
[inst
], aopGet (op1
, offset1
, true));
1395 char *l
= Safe_strdup (aopGet (op1
, offset1
, true));
1396 emit2 ("%s %s, %s", asminstnames
[inst
], l
, aopGet (op2
, offset2
, true));
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);
1407 emit3 (enum asminst inst
, asmop
*op1
, asmop
*op2
)
1409 emit3_o (inst
, op1
, 0, op2
, 0);
1413 emit3w (enum asminst inst
, asmop
*op1
, asmop
*op2
)
1415 emit3w_o (inst
, op1
, 0, op2
, 0);
1419 _emitMove (const char *to
, const char *from
)
1421 if (STRCASECMP (to
, from
) != 0)
1423 emit2 ("ld %s, %s", to
, from
);
1428 // Could leave this to the peephole, but sometimes the peephole is inhibited.
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
])
1442 emit3_o (A_LD
, to
, to_offset
, from
, from_offset
);
1446 static const char *aopNames
[] =
1464 aopDump (const char *plabel
, asmop
* aop
)
1470 emitDebug ("; Dump of %s: type %s size %u", plabel
, aopNames
[aop
->type
], aop
->size
);
1475 emitDebug ("; aop_stk %d", aop
->aopu
.aop_stk
);
1478 for (i
= aop
->size
- 1; i
>= 0; i
--)
1479 *rbp
++ = *(aop
->aopu
.aop_reg
[i
]->name
);
1481 emitDebug ("; reg = %s", regbuf
);
1484 emitDebug ("; pairptr = (%s)", _pairs
[aop
->aopu
.aop_pairId
].name
);
1487 /* No information. */
1494 _moveA (const char *moveFrom
)
1496 _emitMove ("a", moveFrom
);
1499 /* Load aop into A */
1501 _moveA3 (asmop
* from
, int offset
)
1503 _emitMove3 (ASMOP_A
, 0, from
, offset
);
1507 getPairName (asmop
*aop
)
1509 if (aop
->type
== AOP_REG
)
1511 switch (aop
->aopu
.aop_reg
[0]->rIdx
)
1527 wassertl (0, "Tried to get the pair name of something that isn't a pair");
1531 /** Returns TRUE if the registers used in aop form a pair (BC, DE, HL) */
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
1541 isUnsplitable (const asmop
* aop
)
1543 switch (getPairId (aop
))
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 */
1563 spillPairReg (const char *regname
)
1565 if (strlen (regname
) == 1)
1571 spillPair (PAIR_HL
);
1575 spillPair (PAIR_DE
);
1579 spillPair (PAIR_BC
);
1585 /* swap pairs fiels type/base */
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
);
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);
1611 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
1612 _G
.stack
.pushed
+= 2;
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);
1624 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
1625 _G
.stack
.pushed
-= 2;
1631 genMovePairPair (PAIR_ID srcPair
, PAIR_ID dstPair
)
1644 if (srcPair
== PAIR_IX
|| srcPair
== PAIR_IY
)
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);
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 /*-----------------------------------------------------------------*/
1671 newAsmop (short type
)
1675 aop
= traceAlloc (&_G
.trace
.aops
, Safe_alloc (sizeof (asmop
)));
1677 memset (aop
->regs
, -1, 9);
1678 aop
->valinfo
.anything
= true;
1682 /*-----------------------------------------------------------------*/
1683 /* aopForSym - for a true symbol */
1684 /*-----------------------------------------------------------------*/
1686 aopForSym (const iCode
* ic
, symbol
* sym
, bool requires_a
)
1693 wassert (sym
->etype
);
1695 space
= SPEC_OCLS (sym
->etype
);
1697 /* if already has one */
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
);
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
;
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
));
1735 if (IN_REGSP (space
))
1737 /*.p.t.20030716 minor restructure to add SFR support to the Z80 */
1740 /* if it is in direct space */
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); */
1752 /*.p.t.20030716 adding SFR support to the Z80 port */
1753 aop
= newAsmop (AOP_SFR
);
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); */
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
);
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
))
1785 /*-----------------------------------------------------------------*/
1786 /* aopForRemat - rematerializes an object */
1787 /*-----------------------------------------------------------------*/
1789 aopForRemat (symbol
*sym
)
1791 iCode
*ic
= sym
->rematiCode
;
1802 if (isOperandLiteral (IC_RIGHT (ic
)))
1804 val
+= (int) operandLitValue (IC_RIGHT (ic
));
1805 ic
= OP_SYMBOL (IC_LEFT (ic
))->rematiCode
;
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
));
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
;
1838 aop
= newAsmop (AOP_IMMD
);
1840 dbuf_init (&dbuf
, 128);
1843 dbuf_tprintf (&dbuf
, "(%s %c %d)", OP_SYMBOL (IC_LEFT (ic
))->rname
, val
>= 0 ? '+' : '-', abs (val
) & 0xffff);
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
));
1855 #if 0 // No longer used?
1856 /*-----------------------------------------------------------------*/
1857 /* regsInCommon - two operands have some registers in common */
1858 /*-----------------------------------------------------------------*/
1860 regsInCommon (operand
* op1
, operand
* op2
)
1862 symbol
*sym1
, *sym2
;
1865 /* if they have registers in common */
1866 if (!IS_SYMOP (op1
) || !IS_SYMOP (op2
))
1869 sym1
= OP_SYMBOL (op1
);
1870 sym2
= OP_SYMBOL (op2
);
1872 if (sym1
->nRegs
== 0 || sym2
->nRegs
== 0)
1875 for (i
= 0; i
< sym1
->nRegs
; i
++)
1881 for (j
= 0; j
< sym2
->nRegs
; j
++)
1886 if (sym2
->regs
[j
] == sym1
->regs
[i
])
1895 /*-----------------------------------------------------------------*/
1896 /* operandsEqu - equivalent */
1897 /*-----------------------------------------------------------------*/
1899 operandsEqu (operand
* op1
, operand
* op2
)
1901 symbol
*sym1
, *sym2
;
1903 /* if they not symbols */
1904 if (!IS_SYMOP (op1
) || !IS_SYMOP (op2
))
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
)
1915 /* if they are the same */
1919 if (sym1
->rname
[0] && sym2
->rname
[0] && strcmp (sym1
->rname
, sym2
->rname
) == 0)
1922 /* if left is a tmp & right is not */
1923 if (IS_ITEMP (op1
) && !IS_ITEMP (op2
) && sym1
->isspilt
&& (sym1
->usl
.spillLoc
== sym2
))
1926 if (IS_ITEMP (op2
) && !IS_ITEMP (op1
) && sym2
->isspilt
&& sym1
->level
> 0 && (sym2
->usl
.spillLoc
== sym1
))
1932 /*-----------------------------------------------------------------*/
1933 /* sameRegs - two asmops have the same registers */
1934 /*-----------------------------------------------------------------*/
1936 sameRegs (const asmop
*aop1
, const asmop
*aop2
)
1940 if (aop1
->type
== AOP_SFR
|| aop2
->type
== AOP_SFR
)
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
)
1954 if (aop1
->size
!= aop2
->size
)
1957 for (i
= 0; i
< aop1
->size
; i
++)
1958 if (aop1
->aopu
.aop_reg
[i
] != aop2
->aopu
.aop_reg
[i
])
1964 /*-----------------------------------------------------------------*/
1965 /* aopSame - two asmops refer to the same storage */
1966 /*-----------------------------------------------------------------*/
1968 aopSame (const asmop
*aop1
, int offset1
, const asmop
*aop2
, int offset2
, int size
)
1970 if (aop1
== aop2
&& offset1
== offset2
)
1973 for(; size
; size
--, offset1
++, offset2
++)
1975 if (offset1
>= aop1
->size
|| offset2
>= aop2
->size
)
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
)
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
)
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
))
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
))
2002 /*-----------------------------------------------------------------*/
2003 /* aopOp - allocates an asmop for an operand : */
2004 /*-----------------------------------------------------------------*/
2006 aopOp (operand
*op
, const iCode
*ic
, bool result
, bool requires_a
)
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
));
2022 op
->aop
->valinfo
= getOperandValinfo (ic
, op
);
2023 else if(ic
->resultvalinfo
)
2024 op
->aop
->valinfo
= *ic
->resultvalinfo
;
2028 /* if already has a asmop then continue */
2031 if (op
->aop
->type
== AOP_SFR
)
2033 op
->aop
->bcInUse
= isPairInUse (PAIR_BC
, ic
);
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
);
2049 op
->aop
->valinfo
.anything
= true;
2053 /* if this is a true symbol */
2054 if (IS_TRUE_SYMOP (op
))
2056 op
->aop
= aopForSym (ic
, OP_SYMBOL (op
), requires_a
);
2058 op
->aop
->valinfo
= getOperandValinfo (ic
, op
);
2059 else if(ic
->resultvalinfo
)
2060 op
->aop
->valinfo
= *ic
->resultvalinfo
;
2064 /* this is a temporary : this has
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
);
2082 /* if it is spilt then two situations
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 */
2094 sym
->aop
= op
->aop
= aop
= aopForRemat (sym
);
2095 aop
->size
= getSize (sym
->type
);
2097 aop
->valinfo
= getOperandValinfo (ic
, op
);
2098 else if(ic
->resultvalinfo
)
2099 aop
->valinfo
= *ic
->resultvalinfo
;
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
);
2109 aop
->valinfo
= getOperandValinfo (ic
, op
);
2110 else if(ic
->resultvalinfo
)
2111 aop
->valinfo
= *ic
->resultvalinfo
;
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
);
2134 aop
->valinfo
= getOperandValinfo (ic
, op
);
2135 else if(ic
->resultvalinfo
)
2136 aop
->valinfo
= *ic
->resultvalinfo
;
2140 /* else must be a dummy iTemp */
2141 sym
->aop
= op
->aop
= aop
= newAsmop (AOP_DUMMY
);
2142 aop
->size
= getSize (sym
->type
);
2144 aop
->valinfo
= getOperandValinfo (ic
, op
);
2145 else if(ic
->resultvalinfo
)
2146 aop
->valinfo
= *ic
->resultvalinfo
;
2150 /* must be in a register */
2151 sym
->aop
= op
->aop
= aop
= newAsmop (AOP_REG
);
2152 aop
->size
= sym
->nRegs
;
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.");
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.
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
);
2183 if (FUNC_SDCCCALL (ftype
) == 0 || FUNC_ISSMALLC (ftype
) || FUNC_ISZ88DK_FASTCALL (ftype
))
2187 return (IS_SM83
? ASMOP_E
: ASMOP_L
);
2189 return (IS_SM83
? ASMOP_DE
: ASMOP_HL
);
2192 return (IS_SM83
? ASMOP_HLDE
: ASMOP_DEHL
);
2197 wassert (FUNC_SDCCCALL (ftype
) == 1);
2204 if (IS_RAB
|| IS_TLCS90
|| IS_EZ80_Z80
)
2212 return (IS_SM83
? ASMOP_DEBC
: ASMOP_HLDE
);
2218 // Get asmop for registers containing a parameter
2219 // Returns 0 if the parameter is passed on the stack
2221 aopArg (sym_link
*ftype
, int i
)
2223 wassert (IS_FUNC (ftype
));
2225 if (IFFUNC_HASVARARGS (ftype
))
2228 value
*args
= FUNC_ARGS(ftype
);
2231 if (FUNC_ISZ88DK_FASTCALL (ftype
))
2233 if (i
!= 1 || IS_STRUCT (args
->type
))
2236 switch (getSize (args
->type
))
2249 // Old SDCC calling convention: Pass everything on the stack.
2250 if (FUNC_SDCCCALL (ftype
) == 0 || FUNC_ISSMALLC (ftype
) || IFFUNC_ISBANKEDCALL (ftype
))
2253 wassert (FUNC_SDCCCALL (ftype
) == 1);
2255 if (!FUNC_HASVARARGS (ftype
))
2260 for (j
= 1, arg
= args
; j
< i
; j
++, arg
= arg
->next
)
2263 if (IS_STRUCT (arg
->type
))
2266 if (i
== 1 && getSize (arg
->type
) == 1)
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)
2275 if (IS_SM83
&& i
== 2 && aopArg (ftype
, 1) == ASMOP_A
&& getSize (arg
->type
) == 2)
2278 if (IS_SM83
&& i
== 2 && aopArg (ftype
, 1) == ASMOP_DE
&& getSize (arg
->type
) == 1)
2280 if (IS_SM83
&& i
== 2 && aopArg (ftype
, 1) == ASMOP_DE
&& getSize (arg
->type
) == 2)
2283 if (!IS_SM83
&& i
== 2 && aopArg (ftype
, 1) == ASMOP_A
&& getSize (arg
->type
) == 1)
2286 if ((IS_Z80
|| IS_Z180
|| IS_Z80N
|| IS_R800
) && i
== 2 && aopArg (ftype
, 1) == ASMOP_A
&& getSize (arg
->type
) == 2)
2288 if ((IS_Z80
|| IS_Z180
|| IS_Z80N
|| IS_R800
) && i
== 2 && aopArg (ftype
, 1) == ASMOP_HL
&& getSize (arg
->type
) == 2)
2291 if ((IS_RAB
|| IS_TLCS90
|| IS_EZ80_Z80
) && i
== 2 && aopArg (ftype
, 1) == ASMOP_A
&& getSize (arg
->type
) == 2)
2293 if ((IS_RAB
|| IS_TLCS90
|| IS_EZ80_Z80
) && i
== 2 && aopArg (ftype
, 1) == ASMOP_HL
&& getSize (arg
->type
) == 1)
2295 if ((IS_RAB
|| IS_TLCS90
|| IS_EZ80_Z80
) && i
== 2 && aopArg (ftype
, 1) == ASMOP_HLDE
&& getSize (arg
->type
) == 1)
2304 // Return true, iff ftype cleans up stack parameters.
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.
2318 if (!SPEC_REGPARM (arg
->etype
))
2319 stackparmbytes
+= argsize
;
2321 if (!stackparmbytes
)
2324 if (IFFUNC_ISZ88DK_CALLEE (ftype
))
2327 if (FUNC_SDCCCALL (ftype
) == 0 || FUNC_ISSMALLC (ftype
) || FUNC_ISZ88DK_FASTCALL (ftype
))
2330 if (IFFUNC_ISBANKEDCALL (ftype
))
2333 if (FUNC_HASVARARGS (ftype
))
2336 wassert (FUNC_SDCCCALL (ftype
) == 1);
2338 // Callee cleans up stack for all non-vararg functions on sm83.
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)
2345 else if (IS_FLOAT (ftype
->next
) && farg
)
2350 /*-----------------------------------------------------------------*/
2351 /* freeAsmop - free up the asmop given to an operand */
2352 /*----------------------------------------------------------------*/
2354 freeAsmop (operand
* op
, asmop
*aaop
)
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
);
2382 /* all other cases just dealloc */
2388 OP_SYMBOL (op
)->aop
= NULL
;
2389 /* if the symbol has a spill */
2391 SPIL_LOC (op
)->aop
= NULL
;
2398 isLitWord (const asmop
*aop
)
2400 /* if (aop->size != 2)
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);
2423 dbuf_init (&dbuf
, 128);
2426 /* depending on type */
2432 /* PENDING: for re-target */
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
);
2443 dbuf_tprintf (&dbuf
, "%s + %d", aop
->aopu
.aop_immd
, offset
);
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
);
2458 dbuf_tprintf (&dbuf
, with_hash
? "!immedword" : "!constword", (unsigned) (v
& 0xffffu
));
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);
2476 i
= fl
.c
[offset
] | (fl
.c
[offset
+ 1] << 8);
2478 dbuf_tprintf (&dbuf
, with_hash
? "!immedword" : "!constword", i
);
2495 dbuf_destroy (&dbuf
);
2496 fprintf (stderr
, "aop->type: %d\n", aop
->type
);
2497 wassertl (0, "aopGetLitWordLong got unsupported aop->type");
2500 return dbuf_c_str (&dbuf
);
2504 isPtr (const char *s
)
2506 if (!strcmp (s
, "hl"))
2508 if (!strcmp (s
, "ix"))
2510 if (!strcmp (s
, "iy"))
2516 adjustPair (const char *pair
, int *pold
, int new_val
)
2520 while (*pold
< new_val
)
2522 emit2 ("inc %s", pair
);
2525 while (*pold
> new_val
)
2527 emit2 ("dec %s", pair
);
2535 spillPair (PAIR_HL
);
2536 spillPair (PAIR_IY
);
2540 requiresHL (const asmop
*aop
)
2551 return (IS_SM83
|| _G
.omitFramePtr
);
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
)
2563 return (aop
->aopu
.aop_pairId
== PAIR_HL
);
2569 // Updated the internally cached value for a pair.
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.
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);
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;
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
, '+')))
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
2630 adjustPair (pair
, &_G
.pairs
[pairId
].offset
, offset
);
2633 if (pairId
== PAIR_IY
&& offset
== _G
.pairs
[pairId
].offset
)
2635 if (dry
) // Just report matching base
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
)
2656 else if (IS_RAB
&& !new_high
&& (new_low
== 1 && (old_high
|| old_low
)) && f_dead
)
2662 else if (new_high
== old_high
&& new_low
== old_high
)
2664 emit3_o (A_LD
, ASMOP_L
, 0, ASMOP_H
, 0);
2667 else if (new_low
== old_low
&& new_high
== old_low
)
2669 emit3_o (A_LD
, ASMOP_H
, 0, ASMOP_L
, 0);
2672 /* Change lower byte only. */
2673 else if (new_high
== old_high
)
2675 emit3_o (A_LD
, ASMOP_L
, 0, left
, offset
);
2678 /* Change upper byte only. */
2679 else if (new_low
== old_low
)
2681 emit3_o (A_LD
, ASMOP_H
, 0, left
, offset
+ 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
)
2695 cost (1 + 1, 2 + 2);
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);
2703 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
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);
2711 _G
.pairs
[pairId
].base
= traceAlloc (&_G
.trace
.aops
, Safe_strdup (base
));
2712 _G
.pairs
[pairId
].offset
= offset
;
2713 Safe_free (base_str
);
2720 makeFreePairId (const iCode
* ic
, bool * pisUsed
)
2726 if (!bitVectBitValue (ic
->rMask
, B_IDX
) && !bitVectBitValue (ic
->rMask
, C_IDX
))
2730 else if (!IS_SM83
&& !bitVectBitValue (ic
->rMask
, D_IDX
) && !bitVectBitValue (ic
->rMask
, E_IDX
))
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. */
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
)
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);
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);
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
);
2792 else if (aop
->type
== AOP_STL
&& offset
>= 2)
2794 fetchLitPair (pairId
, ASMOP_ZERO
, 0, true, false);
2797 else if (aop
->type
== AOP_STL
)
2803 /* if this is rematerializable */
2804 if (isLitWord (aop
))
2805 fetchLitPair (pairId
, aop
, offset
, true, false);
2808 if (getPairId_o (aop
, offset
) == pairId
)
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
);
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
);
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)
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);
2850 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
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
)
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);
2872 wassertl (aop
->size
- offset
> 1, "Attempted to fetch no data into HL");
2875 emit2 ("ld hl, 0 (hl)");
2878 else if (IS_EZ80_Z80
|| IS_TLCS90
)
2880 emit2 ("ld hl, !*hl");
2881 cost2 (2, 0, 0, 0, 0, 8, 4, 0);
2885 if (ic
&& bitVectBitValue (ic
->rMask
, A_IDX
))
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
))
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
));
2929 PAIR_ID id
= makeFreePairId (ic
, &isUsed
);
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);
2949 else if (isUnsplitable (aop
))
2951 _push (getPairId (aop
));
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. */
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
)))
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);
2995 if (pairId
== PAIR_HL
&& (aopInReg (aop
, offset
, IYL_IDX
) || aopInReg (aop
, offset
, IYH_IDX
)))
2997 if (!aopInReg (aop
, offset
, _pairs
[pairId
].l_idx
))
2999 if (!HAS_IYL_INST
&& (aopInReg (aop
, offset
, IYL_IDX
) || aopInReg (aop
, offset
, IYH_IDX
)))
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
)))
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
)))
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? */
3023 fetchPair (PAIR_ID pairId
, asmop
*aop
)
3025 fetchPairLong (pairId
, aop
, NULL
, 0);
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
)
3036 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
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
)
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
));
3051 cost2 (4 - IS_TLCS90
, 14, 12, 8, 0, 6, 4, 4);
3053 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
3054 dbuf_destroy (&dbuf
);
3055 emit2 ("add %s, sp", _pairs
[lid
].name
);
3057 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
3059 cost2 (1, 11, 7, 2, 8, 8, 1, 1);
3063 wassert (id
== PAIR_DE
|| id
== PAIR_HL
);
3064 emit2 ("!ldahlsp", offset
);
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
)
3085 cost2 (1, 10, 9, 7, 12, 6, 3, 3);
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
)
3103 wassertl (!IS_SM83
, "The SM83 doesn't have an extended stack");
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
);
3111 setupPairFromSP (pairId
, abso
+ _G
.stack
.pushed
);
3113 _G
.pairs
[pairId
].offset
= abso
;
3120 fetchLitPair (pairId
, (asmop
*) aop
, offset
, true, false);
3121 _G
.pairs
[pairId
].offset
= offset
;
3127 shiftIntoPair (pairId
, (asmop
*) aop
); // Legacy. Todo: eliminate uses of shiftIntoPair() ?
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.
3142 setupPair (PAIR_ID pairId
, asmop
*aop
, int offset
)
3147 wassertl (pairId
== PAIR_IY
|| pairId
== PAIR_HL
, "AOP_IY must be in IY or HL");
3148 fetchLitPair (pairId
, aop
, 0, true, false);
3152 wassertl (pairId
== PAIR_HL
, "AOP_HL must be in HL");
3154 fetchLitPair (pairId
, aop
, offset
, true, false);
3155 _G
.pairs
[pairId
].offset
= offset
;
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
);
3174 /* PENDING: Do this better. */
3175 if (_G
.preserveCarry
)
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
)
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
);
3203 setupPairFromSP (PAIR_HL
, abso
+ _G
.stack
.pushed
);
3205 _G
.pairs
[pairId
].offset
= abso
;
3210 if (pairId
!= aop
->aopu
.aop_pairId
)
3211 genMovePairPair (aop
->aopu
.aop_pairId
, pairId
);
3212 adjustPair (_pairs
[pairId
].name
, &_G
.pairs
[pairId
].offset
, offset
);
3218 _G
.pairs
[pairId
].last_type
= aop
->type
;
3222 emitLabelSpill (symbol
*tlbl
)
3228 /*-----------------------------------------------------------------*/
3229 /* aopGet - for fetching value of the aop */
3230 /*-----------------------------------------------------------------*/
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);
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");
3257 /* depending on type */
3261 dbuf_tprintf (&dbuf
, bit16
? "hl" : "a");
3265 /* PENDING: re-target */
3267 dbuf_tprintf (&dbuf
, "!immedword", aop
->aopu
.aop_immd
);
3273 // dbuf_tprintf (&dbuf, "!bankimmeds", aop->aopu.aop_immd); Bank support not fully implemented yet.
3274 dbuf_tprintf (&dbuf
, "!zero");
3278 dbuf_tprintf (&dbuf
, "!msbimmeds", aop
->aopu
.aop_immd
);
3282 dbuf_tprintf (&dbuf
, "!lsbimmeds", aop
->aopu
.aop_immd
);
3286 dbuf_tprintf (&dbuf
, "!zero");
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');
3299 wassertl (!IS_TLCS90
, "TLCS-90 does not have a separate I/O space");
3302 emit2 ("!rldh", aop
->aopu
.aop_dir
, offset
);
3304 dbuf_append_char (&dbuf
, 'a');
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');
3315 /*.p.t.20030716 handling for i/o port read access for Z80 */
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
);
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');
3342 if (aopInReg (aop
, offset
, IY_IDX
))
3343 dbuf_append_str (&dbuf
, "iy");
3346 dbuf_append_str (&dbuf
, aop
->aopu
.aop_reg
[offset
+ 1]->name
);
3347 dbuf_append_str (&dbuf
, aop
->aopu
.aop_reg
[offset
]->name
);
3351 dbuf_append_str (&dbuf
, aop
->aopu
.aop_reg
[offset
]->name
);
3355 setupPair (PAIR_HL
, aop
, offset
);
3356 dbuf_tprintf (&dbuf
, "!*hl");
3361 setupPair (PAIR_IY
, aop
, offset
);
3362 dbuf_tprintf (&dbuf
, "!*iyx", offset
);
3369 setupPair (PAIR_IY
, aop
, offset
);
3370 dbuf_tprintf (&dbuf
, "!*iyx", offset
);
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
;
3381 dbuf_tprintf (&dbuf
, "(sp)");
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
);
3400 if (aop
->aopu
.aop_stk
>= 0)
3401 offset
+= _G
.stack
.param_offset
;
3402 dbuf_tprintf (&dbuf
, "!*ixx", aop
->aopu
.aop_stk
+ offset
);
3407 wassertl (0, "Tried to fetch from a bit variable");
3411 dbuf_append_str (&dbuf
, aopLiteralLong (aop
->aopu
.aop_lit
, offset
, 1 + bit16
));
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
);
3421 dbuf_tprintf (&dbuf
, "!mems", _pairs
[aop
->aopu
.aop_pairId
].name
);
3425 dbuf_destroy (&dbuf
);
3426 fprintf (stderr
, "aop->type: %d\n", aop
->type
);
3427 wassertl (0, "aopGet got unsupported aop->type");
3431 return dbuf_c_str (&dbuf
);
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"))
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))
3454 canAssignToPtr (const char *s
)
3456 if (isRegString (s
))
3458 if (isConstantString (s
))
3464 canAssignToPtr3 (const asmop
*aop
)
3466 if (aop
->type
== AOP_REG
)
3468 if (aop
->type
== AOP_IMMD
|| aop
->type
== AOP_LIT
)
3473 /*-----------------------------------------------------------------*/
3474 /* aopPut - puts a string for a aop */
3475 /*-----------------------------------------------------------------*/
3477 aopPut (asmop
*aop
, const char *s
, int offset
)
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");
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 */
3499 _moveA (s
); /* in case s is volatile */
3505 if (strcmp (s
, "a"))
3506 emit2 ("ld a, %s", s
);
3507 emit2 ("ld (%s+%d),a", aop
->aopu
.aop_dir
, offset
);
3511 wassertl (!IS_TLCS90
, "TLCS-90 does not have a separate I/O space");
3514 // wassert (IS_SM83);
3515 if (strcmp (s
, "a"))
3516 emit2 ("ld a, %s", s
);
3517 emit2 ("!lldh", aop
->aopu
.aop_dir
, offset
);
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
3528 emit2 ("ld !mems,a", aop
->aopu
.aop_dir
);
3529 emit2 ("nop"); /* Workaround for Rabbit 2000 hardware bug. see TN302 for details. */
3533 /*.p.t.20030716 handling for i/o port read access for Z80 */
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
);
3546 emit2 ("ld bc, !hashedstr", aop
->aopu
.aop_dir
);
3547 emit2 ("out (c), %s", s
);
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
);
3563 if (strcmp (s
, "a"))
3564 emit2 ("ld a, %s", s
);
3565 emit2 ("out (%s), a", aop
->aopu
.aop_dir
);
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
);
3576 emit2 ("ld %s, %s", aop
->aopu
.aop_reg
[offset
]->name
, s
);
3577 spillPairReg (aop
->aopu
.aop_reg
[offset
]->name
);
3582 if (!canAssignToPtr (s
))
3584 emit2 ("ld a, %s", s
);
3585 setupPair (PAIR_IY
, aop
, offset
);
3586 emit2 ("ld !*iyx, a", offset
);
3590 setupPair (PAIR_IY
, aop
, offset
);
3591 emit2 ("ld !*iyx, %s", offset
, s
);
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");
3603 else if (strstr (s
, "(ix)") || strstr (s
, "(iy)"))
3605 emit2 ("ld a, %s", s
);
3608 setupPair (PAIR_HL
, aop
, offset
);
3610 emit2 ("ld !*hl, %s", s
);
3617 if (!canAssignToPtr (s
))
3619 emit2 ("ld a, %s", s
);
3620 setupPair (PAIR_IY
, aop
, offset
);
3621 emit2 ("ld !*iyx, a", offset
);
3625 setupPair (PAIR_IY
, aop
, offset
);
3626 emit2 ("ld !*iyx, %s", offset
, s
);
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");
3640 pointPairToAop (PAIR_HL
, aop
, offset
);
3641 if (!canAssignToPtr (s
))
3643 emit2 ("ld a, %s", s
);
3644 emit2 ("ld !*hl, a");
3647 emit2 ("ld !*hl, %s", s
);
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
);
3660 emit2 ("ld !*ixx, %s", aop
->aopu
.aop_stk
+ offset
, s
);
3666 /* if bit variable */
3667 if (!aop
->aopu
.aop_dir
)
3669 emit2 ("ld a, !zero");
3674 /* In bit space but not in C - cant happen */
3675 wassertl (0, "Tried to write into a bit variable");
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
);
3686 emit2 ("ld !mems, %s", _pairs
[aop
->aopu
.aop_pairId
].name
, s
);
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");
3695 dbuf_destroy (&dbuf
);
3698 // pop a register pair while not destroying one of the two registers in it (destroying tempreg instead, if available).
3700 poppairwithsavedreg (PAIR_ID pair
, short survivingreg
, short tempreg
)
3704 emit2 ("ld %s, %s", regsZ80
[tempreg
].name
, regsZ80
[survivingreg
].name
);
3705 ld_cost (ASMOP_L
, 0, ASMOP_H
, 0, true);
3707 emit2 ("ld %s, %s", regsZ80
[survivingreg
].name
, regsZ80
[tempreg
].name
);
3708 ld_cost (ASMOP_L
, 0, ASMOP_H
, 0, true);
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);
3727 // Move, but try not to. Preserves flags. Cannot use xor to zero, since xor resets the carry flag.
3729 cheapMove (asmop
*to
, int to_offset
, asmop
*from
, int from_offset
, bool a_dead
)
3732 emitDebug ("; cheapMove");
3735 if (aopInReg (to
, to_offset
, A_IDX
))
3738 if (from
->type
== AOP_STL
)
3740 if (from_offset
> 2)
3742 cheapMove (to
, to_offset
, ASMOP_ZERO
, 0, a_dead
);
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
)
3755 if (!pushed_a
) // Preserve f
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);
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
);
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
])
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
);
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
)
3802 cheapMove (to
, to_offset
, ASMOP_A
, 0, true);
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
);
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);
3820 else if (to_index
&& HAS_IYL_INST
)
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
);
3834 if (to
->type
== AOP_REG
&& from_index
&& !to_index
&& - _G
.stack
.pushed
- _G
.stack
.offset
>= -128 && !_G
.omitFramePtr
)
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
);
3844 else if (to_index
&& !from_index
&& from
->type
== AOP_REG
&& - _G
.stack
.pushed
- _G
.stack
.offset
>= -128 && !_G
.omitFramePtr
)
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);
3854 if (from_index
&& !to_index
&& !aopInReg (to
, to_offset
, L_IDX
) && !aopInReg (to
, to_offset
, H_IDX
))
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);
3865 else if (to_index
&& !from_index
&& !aopInReg (from
, from_offset
, L_IDX
) && !aopInReg (from
, from_offset
, H_IDX
))
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);
3876 else if (from_index
&& !to_index
)
3878 wassert (aopInReg (to
, to_offset
, L_IDX
) || aopInReg (to
, to_offset
, H_IDX
));
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
);
3890 else if (to_index
&& !from_index
)
3892 wassert (aopInReg (from
, from_offset
, L_IDX
) || aopInReg (from
, from_offset
, H_IDX
));
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
);
3904 else if (to_index
&& from_index
)
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);
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
;
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);
3931 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
3933 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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
)
3959 cheapMove (ASMOP_A
, 0, from
, from_offset
, true);
3960 cheapMove (to
, to_offset
, ASMOP_A
, 0, true);
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);
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
)
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
);
3991 cost2 (2, 23, 19, 15, 0, 14, 6, 6);
3993 cost2 (1 + IS_RAB
, 19, 16, 15, 0, 14, 5, 5);
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);
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
);
4015 else if (!regalloc_dry_run
&& (aop
->type
== AOP_STK
|| aop
->type
== AOP_EXSTK
) && !sp_offset
)
4018 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
4020 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
4021 emit2 ("push %s", _pairs
[id
].name
);
4023 cost2 (2, 15, 13, 12, 0, 8, 4, 5);
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
))
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
))
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
);
4053 cost2 (3, 16, 16, 13, 0, 0, 5, 5);
4055 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
4062 cheapMove (aop
, 0, ASMOP_C
, 0, true);
4063 cheapMove (aop
, 1, ASMOP_B
, 0, true);
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
);
4073 cheapMove (aop
, 0, ASMOP_E
, 0, true);
4074 cheapMove (aop
, 1, ASMOP_D
, 0, true);
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
);
4096 cheapMove (aop
, 0, ASMOP_L
, 0, true);
4097 cheapMove (aop
, 1, ASMOP_H
, 0, true);
4101 cheapMove (aop
, 0, ASMOP_IYL
, 0, true);
4102 cheapMove (aop
, 1, ASMOP_IYH
, 0, true);
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 /*-----------------------------------------------------------------*/
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);
4131 if (!aopOnStack (result
, roffset
+ i
, 1) || !aopOnStack (source
, soffset
+ i
, 1))
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.
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
)
4158 emit2 ("ld hl, %d (sp)", source_sp_offset
);
4160 emit2 ("ld hl, %s", aopGet (source
, soffset
+ i
, false));
4162 emit2 ("ld %d (sp), hl", result_sp_offset
);
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
);
4171 assigned
[i
+ 1] = true;
4177 if (a_free
|| really_do_it_now
)
4179 if ((requiresHL (result
) || requiresHL (source
)) && !hl_free
)
4181 cheapMove (result
, roffset
+ i
, source
, soffset
+ i
, a_free
);
4182 if ((requiresHL (result
) || requiresHL (source
)) && !hl_free
)
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 /*-----------------------------------------------------------------*/
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
);
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
])
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
);
4250 assigned
[i
+ 1] = true;
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);
4263 assigned
[i
+ 1] = true;
4268 else if (IS_RAB
&& i
+ 1 < n
&& aopOnStack (result
, roffset
+ i
, 2) && aopInReg (source
, soffset
+ i
, IY_IDX
) &&
4271 emit2 ("ld %d (sp), iy", sp_offset
);
4272 cost2 (3, 0, 0, 13, 0, 0, 0, 0);
4274 assigned
[i
+ 1] = true;
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
);
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
);
4287 assigned
[i
+ 1] = true;
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
);
4304 assigned
[i
+ 1] = true;
4309 else if (!IS_SM83
&& i
+ 1 < n
&& aopOnStack (result
, roffset
+ i
, 2) && requiresHL (result
) &&
4310 aopInReg (source
, soffset
+ i
, HL_IDX
) && hl_free
)
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);
4320 assigned
[i
+ 1] = true;
4325 else if (aopOnStack (result
, roffset
+ i
, 1) && requiresHL (result
) && !hl_free
)
4328 cheapMove (result
, roffset
+ i
, source
, soffset
+ i
, a_free
);
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
);
4343 else // This byte is not a register-to-stack copy.
4347 // Copy (stack-to-stack) what we can with whatever free regs we have.
4350 for (int i
= 0; i
< n
; i
++)
4358 offset
= soffset
+ i
;
4363 offset
= roffset
+ i
;
4366 if (aopInReg (operand
, offset
, A_IDX
))
4368 else if (aopInReg (operand
, offset
, L_IDX
) || aopInReg (operand
, offset
, H_IDX
))
4371 genCopyStack (result
, roffset
, source
, soffset
, n
, assigned
, &size
, a_free
, hl_free
, false);
4373 // Now do the register shuffling.
4376 // Rabbits: ld hl, iy; ld iy, hl
4377 // TLCS-90 ld rr, rr
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])
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
);
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
);
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
));
4424 assigned
[i
+ 1] = true;
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
++)
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
)))
4442 if (!assigned
[i
] && aopInReg (source
, soffset
+ i
, E_IDX
))
4443 if (aopInReg (result
, roffset
+ i
, L_IDX
))
4447 if (!assigned
[i
] && aopInReg (source
, soffset
+ i
, L_IDX
))
4448 if (aopInReg (result
, roffset
+ i
, E_IDX
))
4452 if (!assigned
[i
] && aopInReg (source
, soffset
+ i
, D_IDX
))
4453 if (aopInReg (result
, roffset
+ i
, H_IDX
))
4457 if (!assigned
[i
] && aopInReg (source
, soffset
+ i
, H_IDX
))
4458 if (aopInReg (result
, roffset
+ i
, D_IDX
))
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
);
4471 assigned
[ex
[0]] = TRUE
;
4473 assigned
[ex
[1]] = TRUE
;
4475 assigned
[ex
[2]] = TRUE
;
4477 assigned
[ex
[3]] = TRUE
;
4483 while (regsize
&& result
->type
== AOP_REG
&& source
->type
== AOP_REG
)
4487 // Find lowest byte that can be assigned and needs to be assigned.
4488 for (i
= 0; i
< n
; i
++)
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.
4507 cheapMove (result
, roffset
+ i
, source
, soffset
+ i
, false); // We can safely assign a byte.
4511 if (aopInReg (result
, roffset
+ i
, A_IDX
))
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);
4526 for (i
= 0; i
< n
; i
++)
4530 wassertl_bt (i
!= n
, "genCopy error: Trying to cache non-existent byte in accumulator.");
4531 if (!a_free
&& !pushed_a
)
4536 cheapMove (ASMOP_A
, 0, source
, soffset
+ i
, true);
4543 // Copy (stack-to-stack) what we can with whatever free regs we have now.
4546 for (int i
= 0; i
< n
; i
++)
4550 if (aopInReg (result
, roffset
+ i
, A_IDX
))
4552 else if (aopInReg (result
, roffset
+ i
, L_IDX
) || aopInReg (result
, roffset
+ i
, H_IDX
))
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
);
4575 emit2 ("ld hl, %s", aopGet (source
, soffset
+ i
, false));
4578 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
4579 spillPair (PAIR_HL
);
4580 spillPair (PAIR_DE
);
4582 assigned
[i
+ 1] = true;
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
;
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);
4615 assigned
[i
+ 1] = true;
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);
4628 assigned
[i
+ 1] = true;
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
);
4640 assigned
[i
+ 1] = true;
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.
4658 spillPair (extrapair
);
4660 assigned
[i
+ 1] = true;
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
) &&
4670 emit2 ("ex de, hl");
4671 if (!regalloc_dry_run
)
4672 if (sp_offset
<= 255)
4673 emit2 ("ld hl, %d (sp)", sp_offset
);
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
);
4683 emit3_o (A_LD
, result
, roffset
+ i
, ASMOP_L
, 0);
4684 emit3_o (A_LD
, result
, roffset
+ i
+ 1, ASMOP_H
, 0);
4687 assigned
[i
+ 1] = true;
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
)
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);
4708 assigned
[i
+ 1] = true;
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
)))
4719 cheapMove (ASMOP_A
, 0, source
, soffset
+ i
, true);
4721 cheapMove (result
, roffset
+ i
, ASMOP_A
, 0, true);
4727 if (requiresHL (source
) && !hl_free
)
4729 cheapMove (result
, roffset
+ i
, source
, soffset
+ i
, a_free
);
4730 if (requiresHL (source
) && source
->type
!= AOP_REG
&& !hl_free
)
4737 else // This byte is not a register-to-stack copy.
4741 // Free a reg to copy (stack-to-stack) whatever is left.
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
);
4748 genCopyStack (result
, roffset
, source
, soffset
, n
, assigned
, &size
, true, hl_free
, true);
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.
4761 if (cached_byte
!= -1)
4762 cheapMove (result
, roffset
+ cached_byte
, ASMOP_A
, 0, true);
4768 /*-----------------------------------------------------------------*/
4769 /* genMove_o - Copy part of one asmop to another */
4770 /*-----------------------------------------------------------------*/
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
)
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
))
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
);
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
);
4801 bool zeroed_a
= false;
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
);
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);
4826 else if (source
->type
== AOP_STL
&& !(soffset
+ i
) && getPairId_o(result
, roffset
) == PAIR_IY
)
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);
4835 spillPair (PAIR_IY
);
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.
4842 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
4844 spillPair (PAIR_HL
);
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);
4853 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
4854 spillPair (PAIR_DE
);
4858 else if (source
->type
== AOP_STL
)
4860 if (!hl_dead
&& (result
->regs
[L_IDX
] > roffset
|| result
->regs
[H_IDX
] > roffset
))
4864 if (i
+ soffset
> 1)
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);
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
);
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;
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
);
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);
4912 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
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);
4923 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
4924 spillPair (getPairId_o(result
, roffset
+ i
));
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);
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
);
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
)
4953 else if ((aopInReg (result
, roffset
+ i
, E_IDX
) || aopInReg (result
, roffset
+ i
, D_IDX
)) && de_dead
&& !a_dead
)
4955 else if ((aopInReg (result
, roffset
+ i
, L_IDX
) || aopInReg (result
, roffset
+ i
, H_IDX
)) && hl_dead
)
4957 else if ((aopInReg (result
, roffset
+ i
, IYL_IDX
) || aopInReg (result
, roffset
+ i
, IYH_IDX
)) && iy_dead
)
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);
4966 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
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
);
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
)
5001 cheapMove (result
, roffset
+ i
, ASMOP_A
, 0, false);
5002 if (requiresHL (result
) && result
->type
!= AOP_REG
&& !hl_dead
)
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
);
5012 bool pushed_hl
= 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));
5030 emit2 ("ld a, !mems", aopGetLitWordLong (source
, soffset
+ i
, false));
5031 cost2 (3 + IS_TLCS90
, 13, 12, 9, 16, 10, 4, 4);
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
)
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);
5053 else if (result
->type
== AOP_IY
&& !iy_dead
&& !aopInReg (source
, soffset
+ i
, A_IDX
))
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.
5063 bool save_iy
= !iy_dead
&& source
->type
== AOP_IY
&& (result
->type
== AOP_REG
&& !via_a
&& !aopInReg (result
, roffset
+ i
, A_IDX
));
5066 cheapMove (via_a
? ASMOP_A
: result
, via_a
? 0 : (roffset
+ i
), source
, soffset
+ i
, via_a
|| a_dead
);
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);
5084 cheapMove (result
, roffset
+ i
, ASMOP_A
, 0, true);
5089 cheapMove (result
, roffset
+ i
, ASMOP_A
, 0, true);
5100 /*-----------------------------------------------------------------*/
5101 /* genMove - Copy the value from one asmop to another */
5102 /*-----------------------------------------------------------------*/
5104 genMove (asmop
*result
, asmop
*source
, bool a_dead
, bool hl_dead
, bool de_dead
, bool iy_dead
)
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 /*--------------------------------------------------------------------------*/
5114 adjustStack (int n
, bool af_free
, bool bc_free
, bool de_free
, bool hl_free
, bool iy_free
)
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;
5133 loop_cycles
= n
/ 2 * 7 + n
% 2 * 2;
5135 loop_cycles
= n
/ 2 * 12 + n
% 2 * 8;
5137 loop_cycles
= n
/ 2 * 4 + n
% 2;
5139 loop_cycles
= n
/ 2 * 10 + n
% 2 * 6;
5141 else // Assume sequence of inc / dec sp
5143 loop_bytes
= abs(n
);
5145 loop_cycles
= abs(n
) * 2;
5147 loop_cycles
= abs(n
) * 8;
5149 loop_cycles
= abs(n
);
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
);
5160 else if ((optimize
.codeSpeed
?
5161 (loop_cycles
>= (IS_RAB
? 10 : IS_SM83
? 28 : 27)) :
5162 (loop_bytes
>= 5)) &&
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);
5172 else if ((optimize
.codeSpeed
?
5173 (loop_cycles
>= (IS_RAB
? 14 : 35)) :
5174 (loop_bytes
>= 7)) &&
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);
5186 else if ((optimize
.codeSpeed
?
5187 (loop_cycles
>= (IS_RAB
? 16 : 39)) :
5188 (loop_bytes
>= (IS_TLCS90
? 7 : 8))) &&
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);
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
);
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
5224 emit2 ("add sp, !immed%d", d
);
5225 cost (2, IS_SM83
? 16 : 4);
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
))
5233 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5236 else if (!IS_SM83
&& n
<= -2 && ((IS_Z80
|| IS_Z80N
) || optimize
.codeSize
))
5239 cost2 (1, 10, 11, 7, 12, 10, 3, 4);
5242 else if (!IS_SM83
&& n
>= 2 && bc_free
&& ((IS_Z80
|| IS_Z80N
) || optimize
.codeSize
))
5245 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5248 else if (!IS_SM83
&& n
>= 2 && de_free
&& ((IS_Z80
|| IS_Z80N
) || optimize
.codeSize
))
5251 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5254 else if (!IS_SM83
&& n
>= 2 && hl_free
&& ((IS_Z80
|| IS_Z80N
) || optimize
.codeSize
))
5257 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
5260 else if (IS_TLCS90
&& n
>= 2 && iy_free
&& optimize
.codeSize
)
5269 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5275 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5283 /** Put Acc into a register set
5286 outAcc (operand
* result
)
5288 int size
= result
->aop
->size
;
5291 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
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
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.
5310 emit3 (A_LD
, ASMOP_A
, ASMOP_ZERO
);
5311 emit3 (A_RLA
, 0, 0);
5316 /*-----------------------------------------------------------------*/
5317 /* toBoolean - emit code for or a,operator(sizeop) */
5318 /*-----------------------------------------------------------------*/
5320 _toBoolean (const operand
*oper
, bool needflag
)
5322 int size
= oper
->aop
->size
;
5323 sym_link
*type
= operandType (oper
);
5326 if (size
== 1 && needflag
)
5328 cheapMove (ASMOP_A
, 0, oper
->aop
, 0, true);
5329 emit3 (A_OR
, ASMOP_A
, ASMOP_A
);
5333 if (size
== 2 && oper
->aop
->type
== AOP_STL
)
5336 genMove (ASMOP_HL
, oper
->aop
, true, false, false, false);
5343 // Special handling to not overwrite a.
5344 if (oper
->aop
->regs
[A_IDX
] >= 0)
5345 skipbyte
= oper
->aop
->regs
[A_IDX
];
5348 cheapMove (ASMOP_A
, 0, oper
->aop
, size
- 1, true);
5349 skipbyte
= size
- 1;
5352 if (IS_FLOAT (type
))
5354 if (skipbyte
!= size
- 1)
5356 emit2 ("res 7, a"); // clear sign bit
5357 cost2 (2, 8, 7, 4, 8, 4, 2, 2);
5358 skipbyte
= size
- 1;
5361 if (size
!= skipbyte
)
5363 if (!HAS_IYL_INST
&& (aopInReg (oper
->aop
, size
, IYL_IDX
) || aopInReg (oper
->aop
, size
, IYH_IDX
)))
5366 emit3_o (A_OR
, ASMOP_A
, 0, oper
->aop
, size
);
5370 /*-----------------------------------------------------------------*/
5371 /* castBoolean - emit code for casting operand to boolean in a */
5372 /*-----------------------------------------------------------------*/
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
)))
5385 emit3 (A_CP
, ASMOP_A
, right
->aop
);
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. */
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;
5404 int ex
[4] = {-1, -1, -1, -1};
5406 bool pushed_a
= FALSE
;
5410 // Try to use ex de, hl
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
)
5417 for (i
= 0; i
< n
; i
++)
5418 if (dst
[i
] == L_IDX
&& src
[i
] == E_IDX
)
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
)
5424 for (i
= 0; i
< n
; i
++)
5425 if (dst
[i
] == H_IDX
&& src
[i
] == D_IDX
)
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;
5439 // We need to be able to handle any assignment here, ensuring not to overwrite any parts of the source that we still need.
5442 // Find lowest byte that can be assigned and needs to be assigned.
5443 for (i
= 0; i
< n
; i
++)
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.
5464 cheapMove (asmopregs
[dst
[i
]], 0, asmopregs
[src
[i
]], 0, false); // We can safely assign a byte.
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);
5480 for (i
= 0; i
< n
; i
++)
5484 wassertl (i
!= n
, "regMove error: Trying to cache non-existent byte in accumulator.");
5485 if (preserve_a
&& !pushed_a
)
5490 cheapMove (ASMOP_A
, 0, asmopregs
[src
[i
]], 0, true);
5496 if (cached_byte
!= -1)
5497 cheapMove (asmopregs
[dst
[cached_byte
]], 0, ASMOP_A
, 0, true);
5503 /*-----------------------------------------------------------------*/
5504 /* genNot - generate code for ! operation */
5505 /*-----------------------------------------------------------------*/
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);
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
))
5533 emit2 ("adc hl, hl");
5537 else if (IS_RAB
&& left
->aop
->size
== 2 && aopInReg (left
->aop
, 0, HL_IDX
) && isPairDead (PAIR_HL
, ic
))
5541 emit2 ("xor a, #0x01");
5543 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
5547 _toBoolean (left
, FALSE
);
5552 So if A = 0, A-1 = 0xFF and C is set, rotate C into reg. */
5553 emit3 (A_SUB
, ASMOP_A
, ASMOP_ONE
);
5557 /* release the aops */
5558 freeAsmop (left
, NULL
);
5559 freeAsmop (result
, NULL
);
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
;
5574 store de into result
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
);
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
);
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
);
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);
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 */
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
);
5660 if (!isRegDead (A_IDX
, ic
))
5662 if (!de
&& !isRegDead (D_IDX
, ic
))
5664 if (!de
&& !isRegDead (E_IDX
, ic
))
5666 if (!bc
&& !isRegDead (B_IDX
, ic
))
5668 if (!bc
&& !isRegDead (C_IDX
, ic
))
5670 if (!hl
&& !isRegDead (H_IDX
, ic
))
5672 if (!hl
&& !isRegDead (L_IDX
, ic
))
5674 if (!iy
&& !isRegDead (IYH_IDX
, ic
))
5676 if (!iy
&& !isRegDead (IYL_IDX
, ic
))
5682 if (iyh_live
&& iyl_live
)
5683 wassertl (0, "Shouldn't push IY if it's wiped out by the return");
5685 poppairwithsavedreg (PAIR_IY
, IYH_IDX
, -1);
5687 poppairwithsavedreg (PAIR_IY
, IYL_IDX
, -1);
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
);
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 */
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
);
5718 poppairwithsavedreg (PAIR_DE
, E_IDX
, -1);
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
);
5734 poppairwithsavedreg (PAIR_BC
, B_IDX
, -1);
5735 else if (c_live
&& !a_live
&& !IS_TLCS90
)
5737 /* Only restore B */
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
);
5749 poppairwithsavedreg (PAIR_BC
, C_IDX
, -1);
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
);
5769 poppairwithsavedreg (PAIR_HL
, H_IDX
, -1);
5770 else if (l_live
&& !a_live
&& !IS_TLCS90
)
5772 /* Only restore H */
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
);
5788 poppairwithsavedreg (PAIR_HL
, L_IDX
, -1);
5795 _saveRegsForCall (const iCode
*ic
, bool saveHLifused
, bool dontsaveIY
)
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
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
));
5840 _G
.stack
.pushedHL
= TRUE
;
5845 _G
.stack
.pushedBC
= TRUE
;
5850 _G
.stack
.pushedDE
= TRUE
;
5855 _G
.stack
.pushedIY
= TRUE
;
5858 if (!regalloc_dry_run
)
5859 _G
.saves
.saved
= TRUE
;
5863 /* Already saved. */
5867 /*-----------------------------------------------------------------*/
5868 /* genIpush - genrate code for pushing this gets a little complex */
5869 /*-----------------------------------------------------------------*/
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 */
5877 wassertl (0, "Encountered an unsupported spill push.");
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.
5886 iCode
*walk
= ic
->next
;
5890 if (walk
->op
== SEND
&& !_G
.saves
.saved
&& !regalloc_dry_run
)
5892 else if (walk
->op
== CALL
|| walk
->op
== PCALL
)
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
)
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
)
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
)
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);
5931 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5933 else if (isRegDead (A_IDX
, ic
))
5936 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
5937 cheapMove (ASMOP_A
, 0, IC_LEFT (ic
)->aop
, 0, true);
5939 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
5941 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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
);
5955 if (!regalloc_dry_run
)
5956 _G
.stack
.pushed
+= 2;
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);
5983 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
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;
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
)))
6006 /* hl has lower priority on GB, because it's needed for stack access */
6007 if (!IS_SM83
&& hl_free
)
6016 if (IS_SM83
&& requiresHL (IC_LEFT (ic
)->aop
) && IC_LEFT (ic
)->aop
->type
!= AOP_REG
&& de_free
)
6018 else if (IS_SM83
&& requiresHL (IC_LEFT (ic
)->aop
) && IC_LEFT (ic
)->aop
->type
!= AOP_REG
&& bc_free
)
6021 if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, H_IDX
) && l_free
|| h_free
&& aopInReg (IC_LEFT (ic
)->aop
, size
- 2, L_IDX
))
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
))
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
))
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);
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);
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);
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);
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));
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);
6077 cost2 (2, 1, 13, 12, 0, 8, 4, 5);
6080 else if (size
>= 2 && !IS_SM83
)
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
);
6092 else if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, A_IDX
))
6095 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6097 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6100 else if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, B_IDX
))
6103 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6105 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6108 else if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, D_IDX
))
6111 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6113 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6116 else if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, H_IDX
))
6119 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6121 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6124 else if (aopInReg (IC_LEFT (ic
)->aop
, size
- 1, IYH_IDX
))
6127 cost2 (2, 1, 13, 12, 0, 8, 4, 5);
6129 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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);
6136 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6138 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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);
6145 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6147 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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);
6154 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6156 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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);
6163 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6165 cost2 (1, 6, 4, 2, 8, 4, 1, 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));
6173 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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
);
6185 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6191 if (!regalloc_dry_run
)
6192 _G
.stack
.pushed
+= d
;
6197 freeAsmop (IC_LEFT (ic
), NULL
);
6200 /*-----------------------------------------------------------------*/
6201 /* genPointerPush - generate code for pushing */
6202 /*-----------------------------------------------------------------*/
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.
6211 iCode
*walk
= ic
->next
;
6215 if (walk
->op
== SEND
&& !_G
.saves
.saved
&& !regalloc_dry_run
)
6217 else if (walk
->op
== CALL
|| walk
->op
== PCALL
)
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
));
6241 if (!isRegDead (HL_IDX
, ic
) && !(isRegDead (DE_IDX
, ic
) && !IS_SM83
) || !isRegDead (A_IDX
, ic
))
6244 bool swap_de
= !isRegDead (HL_IDX
, ic
);
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);
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);
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);
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);
6279 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6280 _G
.stack
.pushed
+= 2;
6285 emit2 ("ld a, !*hl");
6286 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
6288 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6290 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6291 if (!regalloc_dry_run
)
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.
6299 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
6304 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
6306 freeAsmop (IC_LEFT (ic
), 0);
6309 /* This is quite unfortunate */
6311 setArea (int inHome
)
6314 static int lastArea = 0;
6316 if (_G.in_home != 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;
6324 emit2("!area", CODE_NAME); */
6325 _G
.in_home
= inHome
;
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.
6344 for (walk
= ic
->next
; walk
; walk
= walk
->next
)
6346 if (walk
->op
== CALL
|| walk
->op
== PCALL
)
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
);
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
))
6367 if (walk2
->op
== CALL
|| walk2
->op
== PCALL
)
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
);
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
);
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
;
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);
6430 int fp_offset
, sp_offset
;
6432 if (ic
->op
== PCALL
&& IS_SM83
|| !hl_free
)
6434 aopOp (IC_RESULT (ic
), ic
, true, false);
6435 wassert (IC_RESULT (ic
)->aop
->type
== AOP_STK
|| IC_RESULT (ic
)->aop
->type
== AOP_EXSTK
);
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
);
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);
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);
6457 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
6459 if (ic
->op
== PCALL
&& IS_SM83
|| !hl_free
)
6463 emit3 (A_LD
, ASMOP_E
, ASMOP_L
);
6464 emit3 (A_LD
, ASMOP_D
, ASMOP_H
);
6471 emit3 (A_LD
, ASMOP_C
, ASMOP_L
);
6472 emit3 (A_LD
, ASMOP_B
, ASMOP_H
);
6477 emit2 ("push %s", _pairs
[pair
].name
);
6478 if (pair
== PAIR_IY
)
6479 cost2 (2, 15, 13, 12, 0, 8, 4, 5);
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);
6488 // Check if we can do tail call optimization.
6489 else if (currFunc
&& !IFFUNC_ISISR (currFunc
->type
) &&
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
;
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
)
6546 for (nnic
= nic
->prev
; nnic
; nnic
= nnic
->prev
)
6547 if (nnic
->op
== LABEL
&& IC_LABEL (nnic
)->key
== targetlabel
->key
)
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
))
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
));
6586 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
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");
6597 cost2 (1, 4, 3, 4, 4, 8, 3, 1);
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.
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);
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");
6620 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
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
6632 if (ic
->left
->aop
->regs
[B_IDX
] >= 0 || ic
->left
->aop
->regs
[C_IDX
] >= 0)
6635 if (!regalloc_dry_run
)
6637 tlbl
= newiTempLabel (NULL
);
6638 emit2 ("ld de, !immed!tlabel", labelKey2num (tlbl
->key
));
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
));
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);
6655 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6657 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
6658 if (!regalloc_dry_run
)
6659 _G
.stack
.pushed
-= 2;
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
6668 if (ic
->left
->aop
->regs
[D_IDX
] >= 0 || ic
->left
->aop
->regs
[E_IDX
] >= 0)
6671 if (!regalloc_dry_run
)
6673 tlbl
= newiTempLabel (NULL
);
6674 emit2 ("ld bc, !immed!tlabel", labelKey2num (tlbl
->key
));
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
));
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);
6691 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
6693 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
6694 if (!regalloc_dry_run
)
6695 _G
.stack
.pushed
-= 2;
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;
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;
6741 if (currFunc
&& isFuncCalleeStackCleanup (currFunc
->type
) && prestackadjust
&& !IFFUNC_ISNORETURN (ftype
)) // Copy return value into correct location on stack for tail call optimization.
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
))));
6753 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
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);
6764 emit2 ("defb !constbyte\n", (unsigned)value
);
6766 emit2 ("defw !constword\n", (unsigned)value
);
6767 regalloc_dry_run_cost_bytes
+= 2 + (value
>= 256);
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
));
6774 cost2 (3, 10, 9, 8, 16, 8, 4, 3);
6776 cost2 (3, 17, 16, 12, 24, 14, 5, 3);
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
),
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);
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 /*-----------------------------------------------------------------*/
6833 resultRemat (const iCode
* ic
)
6835 if (SKIP_IC (ic
) || ic
->op
== IFX
)
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
)
6848 /*-----------------------------------------------------------------*/
6849 /* genFunction - generated code for function entry */
6850 /*-----------------------------------------------------------------*/
6852 genFunction (const iCode
* ic
)
6856 symbol
*sym
= OP_SYMBOL (IC_LEFT (ic
));
6859 bool bcInUse
= FALSE
;
6860 bool deInUse
= FALSE
;
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]);
6892 emit2("!bequ", sym
->rname
, bank_number
);
6895 if (IS_STATIC (sym
->etype
))
6896 emit2 ("!functionlabeldef", sym
->rname
);
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.");
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
))
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
)
6934 if (z80_opts
.nmosZ80
)
6935 emit2 ("call ___sdcc_critical_enter");
6938 //get interrupt enable flag IFF2 into P/O
6940 //disable interrupts
6945 _G
.stack
.param_offset
+= 2;
6950 if (z80_opts
.calleeSavesBC
)
6955 /* Detect which registers are used. */
6956 if (IFFUNC_CALLEESAVES (sym
->type
) && sym
->regsUsed
)
6959 for (i
= 0; i
< sym
->regsUsed
->size
; i
++)
6961 if (bitVectBitValue (sym
->regsUsed
, i
))
6977 /* Other systems use DE as a temporary. */
6988 _G
.stack
.param_offset
+= 2;
6991 _G
.calleeSaves
.pushedBC
= bcInUse
;
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;
7008 for (sym
= setFirstItem (istack
->syms
); sym
; sym
= setNextItem (istack
->syms
))
7010 if (sym
->_isparm
&& !IS_REGPARM (sym
->etype
))
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")))
7031 emit2 ("ld ix, !immed%d", -sym
->stack
);
7033 emit2 ("add ix, sp");
7035 emit2 ("ld sp, ix");
7037 emit2 ("lea ix, ix, !immed%d", sym
->stack
);
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
);
7048 emit2 ("ld sp, hl");
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
++)
7067 /*-----------------------------------------------------------------*/
7068 /* genEndFunction - generates epilogue for functions */
7069 /*-----------------------------------------------------------------*/
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.");
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
)
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.
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.
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
);
7116 cost2 (2 + IS_TLCS90
, 0, 0, 9, 0, 12, 0, 0);
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,
7124 iy_free
&& hl_free
);
7125 emit2 (hl_free
? "!jphl" : "jp (iy)");
7127 cost2 (1 + IS_TLCS90
, 4, 3, 4, 4, 8, 3, 1);
7129 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
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);
7138 adjustStack (_G
.stack
.offset
,
7139 !aopRet (sym
->type
) || aopRet (sym
->type
)->regs
[A_IDX
] < 0,
7145 if(!IS_SM83
&& !_G
.omitFramePtr
)
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
)
7155 cost2 (1, 10, 9, 7, 12, 8, 3, 4);
7156 _G
.calleeSaves
.pushedDE
= FALSE
;
7159 if (_G
.calleeSaves
.pushedBC
)
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
))
7171 regalloc_dry_run_cost
++;
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
)
7183 symbol
*tlbl
= newiTempLabel (NULL
);
7185 if (aopRet (sym
->type
) && aopRet (sym
->type
)->regs
[A_IDX
] >= 0) // Preserve return value in a.
7188 emit2 ("ex (sp), hl");
7190 emit2 ("ex (sp), hl");
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
));
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
))
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))
7215 // This has priority since it shows notUsed that A is free
7216 // notUsed can't make assumptions about jp (hl)
7218 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
7220 else if (IS_SM83
&& poststackadjust
== 2 && bc_free
)
7223 cost2 (1, 10, 9, 7, 12, 10, 3, 3);
7227 adjustStack (poststackadjust
,
7228 !aopRet (sym
->type
) || aopRet (sym
->type
)->regs
[A_IDX
] < 0, bc_free
, de_free
, false, iy_free
);
7231 cost2 (1 + IS_TLCS90
, 4, 3, 4, 4, 8, 3, 1);
7234 else if (!IS_SM83
&& iy_free
&& !!IFFUNC_ISISR (sym
->type
))
7237 adjustStack (poststackadjust
, !aopRet (sym
->type
) || aopRet (sym
->type
)->regs
[A_IDX
] < 0, bc_free
, de_free
, hl_free
, false);
7239 cost2 (2, 8, 6, 6, 0, 8, 4, 2);
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)
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);
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);
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);
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);
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,
7325 if (options
.debug
&& currFunc
)
7327 debugFile
->writeEndFunction (currFunc
, ic
, 1);
7330 if (IFFUNC_ISISR (sym
->type
))
7335 cost2 (2, 14, 12, 0, 0, 0, 6, 5);
7339 if (IFFUNC_ISCRITICAL (sym
->type
))
7342 cost2 (1, 4, 3, 0, 4, 2, 1, 1);
7345 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
7349 emit2 (IFFUNC_ISCRITICAL (sym
->type
) ? "reti" : "ret");
7350 cost (1 + IFFUNC_ISCRITICAL (sym
->type
), 16);
7354 if (IFFUNC_ISCRITICAL (sym
->type
) && !is_nmi
)
7357 cost2 (1, 4, 3, 0, 4, 2, 1, 1);
7360 cost2 (2, 14, 12, 12, 16, 14, 6, 5);
7365 /* Both banked and non-banked just ret */
7367 cost2 (1, 10, 9, 8, 16, 10, 5, 3);
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 /*-----------------------------------------------------------------*/
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" */
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 */
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;
7416 value
[1] = lit
&0xff;
7418 value
[2] = lit
&0xff;
7420 value
[3] = lit
&0xff;
7422 if(aopRet (currFunc
->type
) == ASMOP_HLDE
)
7424 regpairs
[0] = PAIR_DE
;
7425 regpairs
[1] = PAIR_HL
;
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];
7444 value
[1] = value
[3];
7448 offset
[0] = offset
[1];
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
);
7458 else if(value
[2] == value
[1])
7460 emit2 ("ld %s, %s", _pairs
[regpairs
[1]].l
, _pairs
[regpairs
[0]].h
);
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
);
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));
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);
7497 emit3w (A_INC
, ASMOP_HL
, 0);
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
;
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;
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);
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
);
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);
7546 emit3w (A_INC
, ASMOP_BC
, 0);
7550 freeAsmop (IC_LEFT (ic
), NULL
);
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 /*-----------------------------------------------------------------*/
7567 genLabel (const iCode
* ic
)
7569 /* special case never generate */
7570 if (IC_LABEL (ic
) == entryLabel
)
7573 emitLabelSpill (IC_LABEL (ic
));
7576 /*-----------------------------------------------------------------*/
7577 /* genGoto - generates a ljmp */
7578 /*-----------------------------------------------------------------*/
7580 genGoto (const iCode
* ic
)
7582 emit2 ("jp !tlabel", labelKey2num (IC_LABEL (ic
)->key
));
7585 /*-----------------------------------------------------------------*/
7586 /* genPlusIncr :- does addition with increment if possible */
7587 /*-----------------------------------------------------------------*/
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
7598 if (IC_RIGHT (ic
)->aop
->type
!= AOP_LIT
)
7601 icount
= (unsigned int) ulFromVal (IC_RIGHT (ic
)->aop
->aopu
.aop_lit
);
7603 /* If result is a pair */
7604 if (resultId
!= PAIR_INVALID
)
7607 if (isLitWord (IC_LEFT (ic
)->aop
))
7609 fetchLitPair (getPairId (IC_RESULT (ic
)->aop
), IC_LEFT (ic
)->aop
, icount
, true, false);
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);
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
));
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);
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);
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);
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);
7664 fetchPair (PAIR_HL
, IC_RIGHT (ic
)->aop
);
7665 emit3w (A_ADD
, ASMOP_HL
, ic
->left
->aop
);
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
))
7679 genMove (IC_RESULT (ic
)->aop
, IC_LEFT (ic
)->aop
, isRegDead (A_IDX
, ic
), isPairDead (PAIR_HL
, ic
), isPairDead (PAIR_DE
, ic
), true);
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);
7688 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
7691 fetchPair (getPairId (IC_RESULT (ic
)->aop
), IC_LEFT (ic
)->aop
);
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);
7702 if (icount
> 4) // Not worth it if the sequence of inc gets too long.
7705 if (icount
> 1 && size
== 1 && aopInReg (IC_LEFT (ic
)->aop
, 0, A_IDX
)) // add a, #n is cheaper than sequence of inc a.
7708 if (size
== 2 && getPairId (IC_LEFT (ic
)->aop
) != PAIR_INVALID
&& icount
<= 3 && isPairDead (getPairId (IC_LEFT (ic
)->aop
), ic
))
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);
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);
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);
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
)))
7731 symbol
*tlbl
= regalloc_dry_run
? 0 : newiTempLabel (0);
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.
7742 if (size
== 1 && getPairId_o (IC_RESULT (ic
)->aop
, offset
) != PAIR_INVALID
)
7744 emit3w_o (A_INC
, ic
->result
->aop
, offset
, 0, 0);
7749 if (!HAS_IYL_INST
&& (aopInReg (IC_RESULT (ic
)->aop
, offset
, IYL_IDX
) || aopInReg (IC_RESULT (ic
)->aop
, offset
, IYH_IDX
)))
7752 emit3_o (A_INC
, IC_RESULT (ic
)->aop
, offset
++, 0, 0);
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
)
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)
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);
7779 if (!HAS_IYL_INST
&& (aopInReg (IC_RESULT (ic
)->aop
, 0, IYL_IDX
) || aopInReg (IC_RESULT (ic
)->aop
, 0, IYH_IDX
)))
7782 emit3_o (A_INC
, IC_RESULT (ic
)->aop
, 0, 0, 0);
7786 /* we can if the aops of the left & result match or
7787 if they are in registers and the registers are the
7789 if (sameRegs (IC_LEFT (ic
)->aop
, IC_RESULT (ic
)->aop
))
7792 emit3 (A_INC
, IC_LEFT (ic
)->aop
, 0);
7799 /*-----------------------------------------------------------------*/
7800 /* outBitAcc - output a bit in acc */
7801 /*-----------------------------------------------------------------*/
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");
7813 if (!regalloc_dry_run
)
7815 emit2 ("jp Z, !tlabel", labelKey2num (tlbl
->key
));
7816 emit2 ("ld a, !one");
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
);
7827 couldDestroyCarry (const asmop
*aop
)
7831 if (aop
->type
== AOP_EXSTK
|| aop
->type
== AOP_IY
)
7840 shiftIntoPair (PAIR_ID id
, asmop
*aop
)
7842 wassertl (!IS_SM83
, "Not implemented for the SM83");
7844 emitDebug ("; Shift into pair");
7849 setupPair (PAIR_HL
, aop
, 0);
7853 setupPair (PAIR_IY
, aop
, 0);
7855 emit2 ("pop %s", _pairs
[id
].name
);
7858 setupPair (PAIR_IY
, aop
, 0);
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
;
7871 setupToPreserveCarry (asmop
*result
, asmop
*left
, asmop
*right
)
7873 wassert (left
&& right
);
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
);
7886 shiftIntoPair (PAIR_IY
, result
);
7889 else if (couldDestroyCarry (right
))
7891 if (getPairId (result
) == PAIR_HL
)
7892 _G
.preserveCarry
= TRUE
;
7894 shiftIntoPair (PAIR_HL
, right
);
7896 else if (couldDestroyCarry (result
))
7898 shiftIntoPair (PAIR_HL
, result
);
7903 /*-----------------------------------------------------------------*/
7904 /* genPlus - generates code for addition */
7905 /*-----------------------------------------------------------------*/
7907 genPlus (iCode
* ic
)
7909 int size
, i
, offset
= 0;
7910 signed char cached
[2];
7911 bool premoved
, started
;
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
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
);
7940 leftop
= IC_LEFT (ic
)->aop
;
7941 rightop
= IC_RIGHT (ic
)->aop
;
7943 /* if both left & right are in bit
7945 if (IC_LEFT (ic
)->aop
->type
== AOP_CRY
&& IC_RIGHT (ic
)->aop
->type
== AOP_CRY
)
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
))
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
)
7977 dbuf_init (&dbuf
, 128);
7978 dbuf_printf (&dbuf
, "!immed(%s + %s)", left
, right
);
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);
7985 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
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
));
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
);
8017 else if (right
== PAIR_HL
&& left
!= PAIR_INVALID
&& (IS_TLCS90
|| left
!= PAIR_IY
))
8019 emit3w (A_ADD
, ASMOP_HL
, ic
->left
->aop
);
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
);
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
);
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);
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);
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);
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);
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);
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
;
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
);
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
)))
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
)))
8116 pair
= isPairDead (PAIR_DE
, ic
) ? PAIR_DE
: PAIR_BC
;
8117 if (!isPairDead (pair
, ic
))
8120 genMove (ASMOP_IY
, IC_LEFT (ic
)->aop
, isRegDead (A_IDX
, ic
), isPairDead (PAIR_HL
, ic
), isPairDead (PAIR_DE
, ic
), true);
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);
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:
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:
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
);
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
);
8199 if (!isPairDead (PAIR_DE
, ic
))
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
};
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
;
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
);
8234 fetchPair (PAIR_DE
, IC_LEFT (ic
)->aop
);
8235 fetchPair (PAIR_HL
, IC_RIGHT (ic
)->aop
);
8237 emit3w (A_ADD
, ASMOP_HL
, ASMOP_DE
);
8241 if (!isRegDead (A_IDX
, ic
))
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
))
8251 if (!isPairDead (PAIR_DE
, ic
))
8254 spillPair (PAIR_HL
);
8255 genMove (IC_RESULT (ic
)->aop
, ASMOP_HL
, isRegDead (A_IDX
, ic
), true, isPairDead (PAIR_DE
, ic
), true);
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
);
8269 // Avoid overwriting operand in h or l when setupToPreserveCarry () loads hl - only necessary if carry is actually used during addition.
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);
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))
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
);
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
);
8321 genMove_o (IC_RESULT (ic
)->aop
, 0, ASMOP_HL
, 0, 2, true, true, de_dead
, false, i
+ 2 == size
);
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
)
8330 if (pair
== PAIR_DE
&& !de_dead
)
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
);
8336 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
8338 if (pair
== PAIR_DE
&& !de_dead
)
8340 genMove_o (IC_RESULT (ic
)->aop
, 0, ASMOP_HL
, 0, 2, true, true, de_dead
, false, i
+ 2 == size
);
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
))
8355 else if (aopInReg (leftop
, i
+ 1, B_IDX
) && aopInReg (rightop
, i
, C_IDX
))
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
))
8362 else if (aopInReg (leftop
, i
, C_IDX
) && aopInReg (rightop
, i
+ 1, B_IDX
))
8366 if (pair
!= PAIR_INVALID
)
8371 emit2 ("adc hl, %s", _pairs
[pair
].name
);
8372 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8376 emit2 (iy
? "add iy, %s" : "add hl, %s", _pairs
[pair
].name
);
8378 if (pair
== PAIR_IY
)
8379 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8381 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
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);
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
);
8405 spillPair (PAIR_HL
);
8406 genMove_o (IC_RESULT (ic
)->aop
, i
, ASMOP_HL
, 0, 2, true, true, de_dead
, true, true);
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
);
8416 spillPair (PAIR_HL
);
8417 genMove_o (IC_RESULT (ic
)->aop
, i
, ASMOP_HL
, 0, 2, true, true, de_dead
, true, true);
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
);
8426 genMove_o (IC_RESULT (ic
)->aop
, i
, ASMOP_HL
, 0, 2, true, true, de_dead
, true, true);
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
);
8435 genMove_o (IC_RESULT (ic
)->aop
, i
, ASMOP_HL
, 0, 2, true, true, de_dead
, true, true);
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
);
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
);
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);
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
);
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
);
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
);
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
);
8496 if (pair
== PAIR_INVALID
)
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;
8503 fetchPairLong (pair
, IC_RIGHT (ic
)->aop
, 0, i
);
8506 emit2 ("adc hl, %s", _pairs
[pair
].name
);
8507 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8511 emit2 ("add hl, %s", _pairs
[pair
].name
);
8513 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
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
;
8528 emit2 ("adc hl, %s", _pairs
[pair
].name
);
8529 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
8533 emit2 ("add hl, %s", _pairs
[pair
].name
);
8535 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
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);
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);
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);
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);
8594 else if (!started
&& !premoved
&& aopIsLitVal (leftop
, i
, 1, 0))
8596 cheapMove (ic
->result
->aop
, i
, rightop
, i
, true);
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
);
8607 leftop
= IC_LEFT (ic
)->aop
;
8608 rightop
= IC_RIGHT (ic
)->aop
;
8610 else // Can't handle both sides in iy.
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
);
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.
8624 cheapMove (ASMOP_A
, 0, leftop
, i
, true);
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);
8636 else if (rightop
->type
== AOP_STL
&& i
< 2)
8639 genMove (ASMOP_HL
, rightop
, false, true, false, false);
8640 emit3 (started
? A_ADC
: A_ADD
, ASMOP_A
, i
? ASMOP_H
: ASMOP_L
);
8644 else if (!HAS_IYL_INST
&& (aopInReg (rightop
, i
, IYL_IDX
) || aopInReg (rightop
, i
, IYH_IDX
)))
8648 emit3_o (started
? A_ADC
: A_ADD
, ASMOP_A
, 0, rightop
, i
);
8653 emit2 ("and a, #0x%02x", topbytemask
);
8654 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
8657 _G
.preserveCarry
= (i
!= size
- 1);
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
++;
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
))
8673 cheapMove (IC_RESULT (ic
)->aop
, i
, ASMOP_A
, 0, true);
8677 cheapMove (IC_RESULT (ic
)->aop
, i
, ASMOP_A
, 0, true);
8681 _G
.preserveCarry
= false;
8683 regalloc_dry_run_state_scale
= 1.0f
;
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.
8693 cheapMove (IC_RESULT (ic
)->aop
, cached
[size
], ASMOP_A
, 0, true);
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 /*-----------------------------------------------------------------*/
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
)
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)
8721 /* if decrement 16 bits in register */
8722 if (sameRegs (left
, result
) && (size
> 1) && isPair (result
))
8726 emit2 ("dec %s", getPairName (result
));
8727 if (getPairId (result
) == PAIR_IY
)
8728 cost2 (2, 10, 7, 4, 0, 4, 2, 2);
8730 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
8735 /* If result is a pair */
8736 if (isPair (IC_RESULT (ic
)->aop
))
8738 fetchPair (getPairId (result
), left
);
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);
8746 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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
);
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);
8769 /* if the sizes are greater than 1 then we cannot */
8770 if (result
->size
> 1 || left
->size
> 1)
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
))
8778 emit3 (A_DEC
, result
, 0);
8782 if (result
->type
== AOP_REG
)
8784 cheapMove (result
, 0, left
, 0, true);
8786 emit3 (A_DEC
, result
, 0);
8793 /*-----------------------------------------------------------------*/
8794 /* genSub - generates code for subtraction */
8795 /*-----------------------------------------------------------------*/
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");
8815 /* if I can do an decrement instead of subtract then GOOD for ME */
8816 if (!maskedtopbyte
&& genMinusDec (ic
, result
, left
, right
) == TRUE
)
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
)
8843 else if (rightp
== PAIR_INVALID
)
8845 else if (leftp
== PAIR_INVALID
)
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);
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
);
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))
8881 setupToPreserveCarry (result
, left
, right
);
8883 /* if literal right, add a, #-lit, else normal subb */
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
))))
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
);
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
);
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);
8918 _G
.preserveCarry
= !!size
;
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
8931 if (aopInReg (left
, offset
, H_IDX
))
8933 else if (aopInReg (left
, offset
, L_IDX
))
8935 else if (!l_dead
&& h_dead
)
8940 bool tmpaop_dead
= aopInReg (tmpaop
, 0, L_IDX
) ? l_dead
: h_dead
;
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);
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
)
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.
8970 else if (right
->type
== AOP_STL
&& offset
< 2)
8972 cheapMove (ASMOP_A
, 0, left
, offset
, true);
8973 if (!hl_dead
&& !pushed_hl
)
8978 genMove (ASMOP_HL
, right
, false, true, false, false);
8979 emit3 (offset
? A_SBC
: A_SUB
, ASMOP_A
, offset
? ASMOP_H
: ASMOP_L
);
8983 if (aopIsLitVal (left
, offset
, 1, 0x00) && aopInReg (right
, offset
, A_IDX
))
8984 emit3 (A_NEG
, 0, 0);
8987 if (aopIsLitVal (left
, offset
, 1, 0x00) && !aopInReg (left
, offset
, A_IDX
))
8988 emit3 (A_XOR
, ASMOP_A
, ASMOP_A
);
8990 cheapMove (ASMOP_A
, 0, left
, offset
, true);
8991 if ((aopInReg (right
, offset
, L_IDX
) || aopInReg (right
, offset
, H_IDX
)) && pushed_hl
)
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
);
9006 cheapMove (ASMOP_A
, 0, left
, offset
, true);
9007 if ((aopInReg (right
, offset
, L_IDX
) || aopInReg (right
, offset
, H_IDX
)) && pushed_hl
)
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
)
9023 cheapMove (ASMOP_A
, 0, left
, offset
, true);
9025 /* first add without previous c */
9028 if (size
== 0 && (unsigned int) (lit
& 0x0FFL
) == 0xFF)
9029 emit3 (A_DEC
, ASMOP_A
, 0);
9032 if (!regalloc_dry_run
)
9033 emit2 ("add a, !immedbyte", (unsigned int)(lit
& 0x0fful
));
9034 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
9038 emit2 ("adc a, !immedbyte", (unsigned int)((lit
>> (offset
* 8)) & 0x0fful
));
9043 emit2 ("and a, #0x%02x", topbytemask
);
9044 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
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
) &&
9055 (aopInReg (result
, offset
, L_IDX
) || aopInReg (result
, offset
, H_IDX
)))
9061 /*-----------------------------------------------------------------*/
9062 /* genMinus - generates code for subtraction */
9063 /*-----------------------------------------------------------------*/
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
;
9086 regalloc_dry_run_cost_states
+= -2.0 * regalloc_dry_run_state_scale
;
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
;
9095 if (!isRegDead (A_IDX
, ic
))
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);
9102 emit2 ("jp NZ, !tlabel", labelKey2num (IC_TRUE (ifx
)->key
));
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.
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 /*-----------------------------------------------------------------*/
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
))
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
))
9142 /*-----------------------------------------------------------------*/
9143 /* genUminus - unary minus code generation */
9144 /*-----------------------------------------------------------------*/
9146 genUminus (const iCode
*ic
)
9149 aopOp (IC_LEFT (ic
), ic
, FALSE
, FALSE
);
9150 aopOp (IC_RESULT (ic
), ic
, TRUE
, FALSE
);
9152 /* if both in bit space then special
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");
9160 if (IS_FLOAT (operandType (IC_LEFT (ic
))))
9161 genUminusFloat (ic
, IC_RESULT (ic
), IC_LEFT (ic
));
9163 genSub (ic
, IC_RESULT (ic
)->aop
, ASMOP_ZERO
, IC_LEFT (ic
)->aop
);
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 /*-----------------------------------------------------------------*/
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.");
9188 wassertl (0, "Multiplication is handled through support function calls on sm83");
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);
9205 cheapMove (ASMOP_B
, 0, IC_LEFT (ic
)->aop
, LSB
, true);
9206 cheapMove (ASMOP_C
, 0, IC_RIGHT (ic
)->aop
, LSB
, true);
9209 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
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);
9223 cheapMove (ASMOP_D
, 0, IC_LEFT (ic
)->aop
, LSB
, true);
9224 cheapMove (ASMOP_E
, 0, IC_RIGHT (ic
)->aop
, LSB
, true);
9227 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
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
))
9237 spillPair (PAIR_HL
);
9238 cost2 (2, 8, 17, 0, 0, 0, 6, 0);
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
));
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);
9260 cheapMove (ASMOP_C
, 0, IC_LEFT (ic
)->aop
, 0, true);
9261 cheapMove (ASMOP_E
, 0, IC_RIGHT (ic
)->aop
, 0, true);
9266 cheapMove (ASMOP_D
, 0, ASMOP_ZERO
, 0, true);
9267 cheapMove (ASMOP_B
, 0, ASMOP_D
, 0, true);
9272 spillPair (PAIR_HL
);
9274 genMove (result
, resultsize
> 1 ? ASMOP_BC
: ASMOP_C
, !isRegDead (A_IDX
, ic
), true, false, true);
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));
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));
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);
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");
9317 if (!isPairDead (PAIR_DE
, ic
))
9320 _G
.stack
.pushedDE
= TRUE
;
9322 if (IS_RAB
&& !isPairDead (PAIR_BC
, ic
) ||
9323 !(IS_Z180
|| IS_EZ80_Z80
) && !isRegDead (B_IDX
, ic
))
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);
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
);
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
);
9357 emit3 (A_LD
, ASMOP_L
, ASMOP_C
);
9358 emit3 (A_LD
, ASMOP_H
, ASMOP_B
);
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
)
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
);
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
;
9386 spillPair (PAIR_HL
);
9392 if (_G
.stack
.pushedDE
)
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 /*----------------------------------------------------------------------*/
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
;
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)
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);
9428 if (left
->aop
->regs
[C_IDX
] >= 0 || left
->aop
->regs
[B_IDX
] >= 0)
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);
9440 genMove (ic
->result
->aop
, ASMOP_HLBC
, isRegDead (A_IDX
, ic
), isPairDead (PAIR_HL
, ic
), true, true);
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);
9453 /*-----------------------------------------------------------------*/
9454 /* genMult - generates code for multiplication */
9455 /*-----------------------------------------------------------------*/
9460 /* If true then the final operation should be a subtract */
9461 bool active
= false;
9463 bool add_in_hl
= false;
9464 int a_cost
= 0, l_cost
= 0;
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
);
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
);
9489 else if (IC_RIGHT (ic
)->aop
->type
!= AOP_LIT
)
9491 genMultOneChar (ic
);
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");
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
)
9509 else if (isRegDead (D_IDX
, ic
) && IC_RESULT (ic
)->aop
->aopu
.aop_reg
[0]->rIdx
== E_IDX
)
9511 else if (isRegDead (B_IDX
, ic
) && IC_RESULT (ic
)->aop
->aopu
.aop_reg
[0]->rIdx
== C_IDX
)
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
))))
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
))))
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
)))
9536 if (IS_Z80N
&& pair
!= PAIR_DE
)
9539 asmop
*pairop
= pair
== PAIR_HL
? ASMOP_HL
: (pair
== PAIR_DE
? ASMOP_DE
: ASMOP_BC
);
9541 if (!isPairDead (pair
, ic
))
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);
9551 cheapMove (ASMOP_L
, 0, IC_LEFT (ic
)->aop
, 0, true);
9552 cheapMove (ASMOP_H
, 0, IC_RIGHT (ic
)->aop
, 0, true);
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);
9560 cheapMove (ASMOP_E
, 0, IC_LEFT (ic
)->aop
, 0, true);
9561 cheapMove (ASMOP_D
, 0, IC_RIGHT (ic
)->aop
, 0, true);
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);
9570 cheapMove (ASMOP_C
, 0, IC_LEFT (ic
)->aop
, 0, true);
9571 cheapMove (ASMOP_B
, 0, IC_RIGHT (ic
)->aop
, 0, true);
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
))
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
))))))
9592 bool active
= false;
9593 unsigned int i
= val
;
9594 for (int count
= 0; count
< 16; count
++)
9596 if (count
!= 0 && active
)
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
);
9612 fetchPairLong (PAIR_DE
, IC_LEFT(ic
)->aop
, ic
, 0);
9613 fetchPair (PAIR_BC
, IC_RIGHT (ic
)->aop
);
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);
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
)
9627 if (isPairDead (PAIR_BC
, ic
) && !(IC_LEFT (ic
)->aop
->type
== AOP_REG
&& IC_LEFT (ic
)->aop
->aopu
.aop_reg
[0]->rIdx
== E_IDX
))
9630 if (pair
== PAIR_DE
&& (byteResult
? !isRegDead (E_IDX
, ic
) : !isPairDead (PAIR_DE
, ic
)))
9633 _G
.stack
.pushedDE
= TRUE
;
9636 /* Use 16-bit additions even for 8-bit result when the operands are in the right places. */
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
);
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);
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);
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));
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
);
9718 emit2 ("add hl, %s", _pairs
[pair
].name
);
9719 cost2 (1 + IS_TLCS90
, 11, 7, 2, 8, 8, 1, 1);
9725 spillPair (PAIR_HL
);
9728 if (_G
.stack
.pushedDE
)
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);
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 /*-----------------------------------------------------------------*/
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 /*-----------------------------------------------------------------*/
9756 genMod (const iCode
* ic
)
9758 /* Shouldn't occur - all done through function calls */
9762 /*-----------------------------------------------------------------*/
9763 /* genIfxJump :- will create a jump depending on the ifx */
9764 /*-----------------------------------------------------------------*/
9766 genIfxJump (iCode
* ic
, char *jval
)
9771 /* if true label then we jump if condition
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);
9782 else if (!strcmp (jval
, "z"))
9786 else if (!strcmp (jval
, "nz"))
9790 else if (!strcmp (jval
, "c"))
9794 else if (!strcmp (jval
, "nc"))
9798 else if (!strcmp (jval
, "m"))
9802 else if (!strcmp (jval
, "p"))
9806 else if (!strcmp (jval
, "po"))
9810 else if (!strcmp (jval
, "pe"))
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);
9824 /* false label is present */
9825 jlbl
= IC_FALSE (ic
);
9826 if (!strcmp (jval
, "a"))
9828 emit3 (A_OR
, ASMOP_A
, ASMOP_A
);
9831 else if (!strcmp (jval
, "z"))
9835 else if (!strcmp (jval
, "nz"))
9839 else if (!strcmp (jval
, "c"))
9843 else if (!strcmp (jval
, "nc"))
9847 else if (!strcmp (jval
, "m"))
9851 else if (!strcmp (jval
, "p"))
9855 else if (!strcmp (jval
, "po"))
9859 else if (!strcmp (jval
, "pe"))
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);
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.
9879 _getPairIdName (PAIR_ID id
)
9881 return _pairs
[id
].name
;
9885 /** Generic compare for > or <
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;
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");
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
);
9923 cheapMove (ASMOP_A
, 0, right
->aop
, 0, true);
9927 cheapMove (ASMOP_A
, 0, right
->aop
, 0, true);
9928 cheapMove (save_b
? ASMOP_C
: ASMOP_B
, 0, ASMOP_A
, 0, true);
9932 cheapMove (ASMOP_A
, 0, left
->aop
, 0, true);
9933 emit3_o (A_SUB
, ASMOP_A
, 0, save_b
? ASMOP_C
: ASMOP_B
, offset
);
9936 result_in_carry
= TRUE
;
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;
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", ullFromVal (left
->aop
->aopu
.aop_lit
) + 1);
9951 cost2 (2, 7, 6, 4, 8, 6, 2, 2);
9952 result_in_carry
= true;
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.
9961 /* No sign so it's always false */
9962 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
9963 result_in_carry
= TRUE
;
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);
9975 cost2 (4 - IS_TLCS90
, 20, 15, 10, 6, 10, 5, 5);
9976 genIfxJump (ifx
, "nz");
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");
9990 genIfxJump (ifx
, "nc");
9993 result_in_carry
= FALSE
;
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
))
10007 pointPairToAop (PAIR_DE
, left
->aop
, 0);
10008 pointPairToAop (PAIR_HL
, right
->aop
, 0);
10012 emit2 ("ld a, !mems", "de");
10013 cost2 (1, 7, 6, 6, 8, 6, 2, 2);
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);
10019 emit3w (A_INC
, ASMOP_HL
, 0);
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
))
10036 spillPair (PAIR_HL
);
10037 result_in_carry
= TRUE
;
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
);
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);
10052 emit3w (A_INC
, ASMOP_HL
, 0);
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
;
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
);
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
);
10079 emit3w (A_INC
, ASMOP_HL
, 0);
10080 updatePair (PAIR_HL
, 1);
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
;
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
))
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
);
10123 cost2 (1, 4, 3, 2, 4, 2, 2, 1);
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;
10141 cheapMove (ASMOP_A
, 0, left
->aop
, offset
, true);
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);
10154 cheapMove (ASMOP_A
, 0, left
->aop
, offset
, true);
10157 emit3 (A_RLA
, 0, 0);
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;
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
);
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
);
10189 cheapMove (ASMOP_A
, 0, left
->aop
, offset
, true);
10190 if (requiresHL (right
->aop
) && right
->aop
->type
!= AOP_REG
&& !isPairDead (PAIR_HL
, ic
))
10197 emit3_o (A_CP
, ASMOP_A
, 0, right
->aop
, offset
);
10199 a_always_byte
= byteOfVal (left
->aop
->aopu
.aop_lit
, offset
);
10202 emit3_o (A_SUB
, ASMOP_A
, 0, right
->aop
, offset
);
10209 /* Subtract through, propagating the carry */
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.
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
);
10226 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
10227 emit3w_o (A_SBC
, ASMOP_HL
, 0, right
->aop
, offset
);
10228 spillPair (PAIR_HL
);
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
);
10241 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
10242 emit3w (A_SBC
, ASMOP_HL
, ASMOP_DE
);
10243 spillPair (PAIR_HL
);
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);
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
);
10280 /* There is no good signed compare in the Z80, so we need workarounds */
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
));
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
));
10319 emitLabelSpill (tlbl2
);
10320 regalloc_dry_run_cost
+= 18;
10321 result_in_carry
= true;
10325 result_in_carry
= true;
10329 if (result
->aop
->type
== AOP_CRY
&& result
->aop
->size
)
10332 if (!result_in_carry
)
10334 /* Shift the sign bit up into carry */
10335 emit3 (A_RLCA
, 0, 0);
10341 /* if the result is used in the next
10342 ifx conditional branch then generate
10343 code a little differently */
10346 if (!result_in_carry
)
10350 genIfxJump (ifx
, "m");
10353 emit3 (A_RLCA
, 0, 0);
10354 genIfxJump (ifx
, "c");
10358 genIfxJump (ifx
, inv
? "nc" : "c");
10363 if (!result_in_carry
)
10365 /* Shift the sign bit up into carry */
10366 emit3 (A_RLCA
, 0, 0);
10370 /* leave the result in acc */
10374 /*-----------------------------------------------------------------*/
10375 /* genCmpGt :- greater than comparison */
10376 /*-----------------------------------------------------------------*/
10378 genCmpGt (iCode
* ic
, iCode
* ifx
)
10380 operand
*left
, *right
, *result
;
10381 sym_link
*letype
, *retype
;
10384 left
= IC_LEFT (ic
);
10385 right
= IC_RIGHT (ic
);
10386 result
= IC_RESULT (ic
);
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))
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
))
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 /*-----------------------------------------------------------------*/
10427 genCmpLt (iCode
* ic
, iCode
* ifx
)
10429 operand
*left
, *right
, *result
;
10430 sym_link
*letype
, *retype
;
10433 left
= IC_LEFT (ic
);
10434 right
= IC_RIGHT (ic
);
10435 result
= IC_RESULT (ic
);
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))
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
))
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 /*-----------------------------------------------------------------*/
10477 gencjneshort (operand
*left
, operand
*right
, symbol
*lbl
, const iCode
*ic
)
10479 int size
= max (left
->aop
->size
, right
->aop
->size
);
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
;
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
))
10504 if (right
->aop
->type
== AOP_LIT
&& !byteOfVal (right
->aop
->aopu
.aop_lit
, 0))
10505 emit3 (A_OR
, ASMOP_A
, ASMOP_A
);
10507 emit3 (A_CP
, ASMOP_A
, right
->aop
);
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
)
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
))
10530 // Test for 0 can be done more efficiently using or
10531 if (!byteOfVal (right
->aop
->aopu
.aop_lit
, offset
))
10535 cheapMove (ASMOP_A
, 0, left
->aop
, offset
, true);
10536 emit3 (A_OR
, ASMOP_A
, ASMOP_A
);
10539 emit3_o (A_OR
, ASMOP_A
, 0, left
->aop
, offset
);
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
);
10560 emit3 (A_INC
, ASMOP_A
, 0);
10561 next_zero
= size
&& !byteOfVal (right
->aop
->aopu
.aop_lit
, offset
+ 1);
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
);
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);
10580 emit3_o (A_SUB
, ASMOP_A
, 0, right
->aop
, offset
);
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.
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
))
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
;
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
);
10643 genMove_o (ASMOP_A
, 0, left
->aop
, offset
, 1, true, false, false, iy_dead
, true);
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)
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
);
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.
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.
10675 /* right is in direct space or a pointer reg, need both a & b */
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
)))
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.
10701 return PAIR_INVALID
;
10704 /*-----------------------------------------------------------------*/
10705 /* gencjne - compare and jump if not equal */
10706 /*-----------------------------------------------------------------*/
10708 gencjne (operand
* left
, operand
* right
, symbol
* lbl
, const iCode
*ic
)
10710 symbol
*tlbl
= regalloc_dry_run
? 0 : newiTempLabel (0);
10713 pop
= gencjneshort (left
, right
, lbl
, ic
);
10716 if (!regalloc_dry_run
)
10718 emit2 ("ld a,!one");
10719 emit2 ("jp !tlabel", labelKey2num (tlbl
->key
));
10720 emitLabelSpill (lbl
);
10724 regalloc_dry_run_cost
+= 6;
10728 /*-----------------------------------------------------------------*/
10729 /* genCmpEq - generates code for equal to */
10730 /*-----------------------------------------------------------------*/
10732 genCmpEq (iCode
* ic
, iCode
* ifx
)
10734 operand
*left
, *right
, *result
;
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
);
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");
10765 symbol
*tlbl
= regalloc_dry_run
? 0 : newiTempLabel (0);
10766 pop
= gencjneshort (left
, right
, tlbl
, ic
);
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
)
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
)
10800 if (!regalloc_dry_run
)
10802 emit2 ("jp !tlabel", labelKey2num (IC_FALSE (ifx
)->key
));
10805 regalloc_dry_run_cost
+= 3;
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");
10818 gencjne (left
, right
, regalloc_dry_run
? 0 : newiTempLabel (NULL
), ic
);
10819 if (result
->aop
->type
== AOP_CRY
&& result
->aop
->size
)
10825 genIfxJump (ifx
, "a");
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);
10835 freeAsmop (left
, NULL
);
10836 freeAsmop (right
, NULL
);
10837 freeAsmop (result
, NULL
);
10840 /*-----------------------------------------------------------------*/
10841 /* genAndOp - for && operation */
10842 /*-----------------------------------------------------------------*/
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");
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
)
10870 outBitAcc (result
);
10873 freeAsmop (left
, NULL
);
10874 freeAsmop (right
, NULL
);
10875 freeAsmop (result
, NULL
);
10878 /*-----------------------------------------------------------------*/
10879 /* genOrOp - for || operation */
10880 /*-----------------------------------------------------------------*/
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");
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
)
10908 outBitAcc (result
);
10911 freeAsmop (left
, NULL
);
10912 freeAsmop (right
, NULL
);
10913 freeAsmop (result
, NULL
);
10916 /*-----------------------------------------------------------------*/
10917 /* isLiteralBit - test if lit == 2^n */
10918 /*-----------------------------------------------------------------*/
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
10934 for (idx
= 0; idx
< 32; idx
++)
10935 if (lit
== pw
[idx
])
10940 /*-----------------------------------------------------------------*/
10941 /* jmpTrueOrFalse - */
10942 /*-----------------------------------------------------------------*/
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.
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;
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 /*-----------------------------------------------------------------*/
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
;
11000 /* if result = right then exchange them */
11001 if (sameRegs (result
->aop
, right
->aop
) && !AOP_NEEDSACC (left
))
11003 operand
*tmp
= right
;
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");
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
;
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);
11035 sizel
= left
->aop
->size
;
11038 /* PENDING: Test case for this. */
11040 cost2 (1, 4, 3, 2, 4, 2, 1, 1);
11044 char *jumpcond
= "NZ";
11046 if ((bytelit
= ((lit
>> (offset
* 8)) & 0x0ffull
)) == 0x00ull
)
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);
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
));
11072 regalloc_dry_run_cost
+= 6;
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
)))
11083 switch (left
->aop
->aopu
.aop_reg
[offset
]->rIdx
)
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);
11105 emit2 ("rl %s", _pairs
[pair
].name
);
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
)
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
)
11125 switch (left
->aop
->aopu
.aop_reg
[offset
]->rIdx
)
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);
11149 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
11151 else if (isLiteralBit (bytelit
) == 7)
11153 emit2 ("rl %s", _pairs
[pair
].name
);
11158 emit2 ("rr %s", _pairs
[pair
].name
);
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
)
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);
11177 cost2 (4, 20 , 15, 10, 6, 10, 5, 5);
11178 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
)
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);
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);
11199 /* Generic case, loading into accumulator and testing there. */
11202 if (!isRegDead (A_IDX
, ic
) || left
->aop
->regs
[A_IDX
] > offset
|| right
->aop
->regs
[A_IDX
] > offset
)
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);
11211 else if (bytelit
!= 0xffu
)
11212 emit3_o (A_AND
, ASMOP_A
, 0, right
->aop
, offset
);
11214 emit3 (A_OR
, ASMOP_A
, ASMOP_A
); /* For the flags */
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
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)
11238 jmpTrueOrFalse (ifx
, tlbl
);
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);
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
))
11269 if (pushed_a
&& (aopInReg (left
->aop
, i
, A_IDX
) || aopInReg (right
->aop
, i
, A_IDX
)))
11272 if (!isRegDead (A_IDX
, ic
))
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;
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
)
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)
11306 cost2 (2, 8, 6, 4, 8, 4, 2, 2); // res b, r
11307 if (aopInReg (result
->aop
, i
, A_IDX
))
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);
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
);
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
);
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
)
11378 if (!HAS_IYL_INST
&& (aopInReg (left
->aop
, i
, IYL_IDX
) || aopInReg (left
->aop
, i
, IYH_IDX
)))
11381 emit3_o (A_AND
, ASMOP_A
, 0, left
->aop
, i
);
11382 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11387 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11389 cheapMove (ASMOP_A
, 0, left
->aop
, i
, true);
11390 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11393 if (requiresHL (right
->aop
) && right
->aop
->type
!= AOP_REG
&& !hl_free
)
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
)))
11404 emit3_o (A_AND
, ASMOP_A
, 0, right
->aop
, i
);
11405 if (requiresHL (right
->aop
) && right
->aop
->type
!= AOP_REG
&& !hl_free
)
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
))
11424 freeAsmop (left
, NULL
);
11425 freeAsmop (right
, NULL
);
11426 freeAsmop (result
, NULL
);
11429 /*-----------------------------------------------------------------*/
11430 /* genOr - code for or */
11431 /*-----------------------------------------------------------------*/
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,
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
;
11472 /* if result = right then exchange them */
11473 if (sameRegs (result
->aop
, right
->aop
) && !AOP_NEEDSACC (left
))
11475 operand
*tmp
= right
;
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");
11491 /* Make sure A is on the left to not overwrite it. */
11492 if (aopInReg (right
->aop
, 0, A_IDX
))
11494 operand
*tmp
= right
;
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);
11506 sizel
= left
->aop
->size
;
11510 wassertl (0, "Result is assigned to a bit");
11512 /* PENDING: Modeled after the AND code which is inefficient. */
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
))
11518 if (!a_free
) // Hard to handle pop with ifx
11521 int bytelit
= (lit
>> (offset
* 8)) & 0x0FFull
;
11523 cheapMove (ASMOP_A
, 0, left
->aop
, offset
, true);
11526 emit3_o (A_OR
, ASMOP_A
, 0, right
->aop
, offset
);
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;
11544 jmpTrueOrFalse (ifx
, tlbl
);
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
))
11560 if (pushed_a
&& (aopInReg (left
->aop
, i
, A_IDX
) || aopInReg (right
->aop
, i
, A_IDX
)))
11563 if (!isRegDead (A_IDX
, ic
))
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);
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);
11588 else if (aopIsLitVal (left
->aop
, i
, 1, 0x00) && !pushed_a
)
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
)
11598 else if (aopIsLitVal (right
->aop
, i
, 1, 0x00) && !pushed_a
)
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
)
11608 else if (aopIsLitVal (left
->aop
, i
, 1, 0xff) || aopIsLitVal (right
->aop
, i
, 1, 0xff))
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
)
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)
11634 cost2 (2, 8, 6, 4, 8, 4, 2, 2); // set b, r
11635 if (aopInReg (result
->aop
, i
, A_IDX
))
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);
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");
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
);
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
);
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");
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);
11725 // Use plain or in a.
11728 wassert (!pushed_a
);
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
)
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
)))
11750 emit3_o (A_OR
, ASMOP_A
, 0, left
->aop
, i
);
11751 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11756 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11758 cheapMove (ASMOP_A
, 0, left
->aop
, i
, true);
11759 if (requiresHL (left
->aop
) && left
->aop
->type
!= AOP_REG
&& !hl_free
)
11762 if (requiresHL (right
->aop
) && right
->aop
->type
!= AOP_REG
&& !hl_free
)
11764 emit3_o (A_OR
, ASMOP_A
, 0, right
->aop
, i
);
11765 if (requiresHL (right
->aop
) && right
->aop
->type
!= AOP_REG
&& !hl_free
)
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
))
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 /*-----------------------------------------------------------------*/
11793 genEor (const iCode
*ic
, iCode
*ifx
, asmop
*result_aop
, asmop
*left_aop
, asmop
*right_aop
)
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
;
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
;
11816 size
= result_aop
->size
;
11818 if (left_aop
->type
== AOP_CRY
)
11820 wassertl (0, "Tried to XOR a bit");
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
;
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);
11839 int sizel
= left_aop
->size
;
11843 /* PENDING: Test case for this. */
11844 wassertl (0, "Tried to XOR left against a literal with the result going into a bit");
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
))
11853 wassert (!pushed_a
);
11857 if (ifx
) // The pop at the end is hard to deal with in case of ifx.
11860 else if (pushed_a
&& (aopInReg (left_aop
, offset
, A_IDX
) || aopInReg (right_aop
, offset
, A_IDX
)))
11863 if (!isRegDead (A_IDX
, ic
))
11869 if (aopInReg (right_aop
, offset
, A_IDX
))
11870 emit3_o (A_XOR
, ASMOP_A
, 0, left_aop
, offset
);
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;
11889 jmpTrueOrFalse (ifx
, tlbl
);
11893 wassertl (0, "Result of XOR was destined for a bit");
11898 // left & result in different registers
11899 if (result_aop
->type
== AOP_CRY
)
11901 wassertl (0, "Result of XOR is in a bit");
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
))
11915 // result = left ^ right
11916 if (aopIsLitVal (right_aop
, i
, 1, 0x00))
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
)
11925 if (!isRegDead (A_IDX
, ic
))
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
))
11934 if (result_aop
->regs
[A_IDX
] >= i
&& result_aop
->regs
[A_IDX
] < end
)
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
);
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");
11957 emit2 (de
? "rl de" : "adc hl, hl");
11958 cost (2 - de
, 4 - 2 * de
);
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");
11970 emit2 (de
? "rr de" : "rr hl");
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
)
11981 if (!isRegDead (A_IDX
, ic
))
11987 // faster than result <- left, anl result,right
11988 // and better if result is SFR
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
)
12003 if (!HAS_IYL_INST
&& (aopInReg (left_aop
, i
, IYL_IDX
) || aopInReg (left_aop
, i
, IYH_IDX
)))
12006 emit3_o (A_XOR
, ASMOP_A
, 0, left_aop
, i
);
12007 if (requiresHL (left_aop
) && left_aop
->type
!= AOP_REG
&& !hl_free
)
12012 if (requiresHL (left_aop
) && left_aop
->type
!= AOP_REG
&& !hl_free
)
12014 cheapMove (ASMOP_A
, 0, left_aop
, i
, true);
12015 if (requiresHL (left_aop
) && left_aop
->type
!= AOP_REG
&& !hl_free
)
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
))
12023 cheapMove (ASMOP_L
, 0, right_aop
, i
, false);
12024 emit3_o (A_XOR
, ASMOP_A
, 0, ASMOP_L
, 0);
12030 if (requiresHL (right_aop
) && right_aop
->type
!= AOP_REG
&& !hl_free
)
12032 emit3_o (A_XOR
, ASMOP_A
, 0, right_aop
, i
);
12033 if (requiresHL (right_aop
) && right_aop
->type
!= AOP_REG
&& !hl_free
)
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
))
12047 if (aopInReg (result_aop
, i
, A_IDX
))
12057 /*-----------------------------------------------------------------*/
12058 /* genXor - code for exclusive or */
12059 /*-----------------------------------------------------------------*/
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 /*-----------------------------------------------------------------*/
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 /*-----------------------------------------------------------------*/
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);
12123 emit2 ("brlc de, b");
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
))
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);
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);
12158 if (!isRegDead (A_IDX
, ic
))
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
);
12171 _moveA (aopGet (left
->aop
, size
- 1, false));
12172 emit3_o (A_RRA
, 0, 0, 0, 0);
12173 aopPut (result
->aop
, "a", size
- 1);
12178 freeAsmop (IC_LEFT (ic
), 0);
12179 freeAsmop (IC_RESULT (ic
), 0);
12182 /*-----------------------------------------------------------------*/
12183 /* genRLC - generate code for rotate left */
12184 /*-----------------------------------------------------------------*/
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
));
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");
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
))
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);
12246 else if (IS_RAB
&& i
+ 1 < size
&& aopInReg (rotaop
, i
, DE_IDX
))
12254 emit3_o (A_RL
, rotaop
, i
, 0, 0);
12258 genMove (result
->aop
, rotaop
, true, isRegDead (HL_IDX
, ic
), isRegDead (DE_IDX
, ic
), isRegDead (IY_IDX
, ic
));
12262 if (!isRegDead (A_IDX
, ic
))
12268 for (int offset
= 0; offset
< size
; ++offset
)
12270 _moveA (aopGet (left
->aop
, offset
, false));
12271 emit3_o (A_RLA
, 0, 0, 0, 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);
12283 freeAsmop (IC_LEFT (ic
), 0);
12284 freeAsmop (IC_RESULT (ic
), 0);
12287 /*-----------------------------------------------------------------*/
12288 /* genGetByte - generates code to get a single byte */
12289 /*-----------------------------------------------------------------*/
12291 genGetByte (const iCode
*ic
)
12293 operand
*left
, *right
, *result
;
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 /*-----------------------------------------------------------------*/
12315 genGetWord (const iCode
*ic
)
12317 operand
*left
, *right
, *result
;
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 /*-----------------------------------------------------------------*/
12339 genGetAbit (const iCode
* ic
)
12341 operand
*left
, *right
, *result
;
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);
12356 if (shCount
== 4 && (IS_SM83
|| IS_Z80N
))
12358 emit3_o (A_SWAP
, ASMOP_A
, 0, 0, 0);
12361 if (result
->aop
->type
== AOP_CRY
)
12365 while (shCount
-- >= 0)
12366 emit3_o (A_RRCA
, 0, 0, 0, 0);
12368 while (shCount
++ < 8)
12369 emit3_o (A_RLCA
, 0, 0, 0, 0);
12375 while (shCount
-- > 0)
12376 emit3_o (A_RRCA
, 0, 0, 0, 0);
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);
12385 freeAsmop (result
, NULL
);
12386 freeAsmop (right
, NULL
);
12387 freeAsmop (left
, NULL
);
12391 emitRsh2 (asmop
* aop
, int size
, int is_signed
)
12398 emit3_o (is_signed
? A_SRA
: A_SRL
, aop
, size
, 0, 0);
12400 emit3_o (A_RR
, aop
, size
, 0, 0);
12405 /*-----------------------------------------------------------------*/
12406 /* shiftR2Left2Result - shift right two bytes from left to result */
12407 /*-----------------------------------------------------------------*/
12409 shiftR2Left2Result (const iCode
*ic
, operand
*left
, int offl
, operand
*result
, int offr
, int shCount
, int is_signed
)
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
);
12421 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
12423 emit2 (op_de
? "rr de" : "rr hl");
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);
12439 emit2 ("srl (hl)");
12440 cost2 (2, 15, 6, 10, 16, 8, 5, 5);
12443 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
12444 emit3 (A_RRD
, 0, 0);
12448 cost2 (2, 15, 6, 10, 16, 8, 5, 5);
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
);
12459 emit2 ("ld hl, !immedword", 0xffffu
>> shCount
);
12462 fetchPair (PAIR_HL
, left
->aop
);
12463 emit2 ("ld de, !immedword", 0xffffu
>> shCount
);
12465 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
12468 emit2 (op_de
? "rr de" : "rr hl");
12471 emit2 ("and hl, de");
12473 genMove (IC_RESULT (ic
)->aop
, ASMOP_HL
, true, true, isPairDead (PAIR_DE
, ic
), true);
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
));
12487 if (!regalloc_dry_run
)
12490 genMove (result
->aop
, ASMOP_HL
, isRegDead (A_IDX
, ic
), true, isRegDead (DE_IDX
, ic
), isRegDead (IY_IDX
, ic
));
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
));
12507 cost2 (3, 11.5, 9.0, 7.0, 12.0, 7.0, 3.0, 3.0);
12508 if (!regalloc_dry_run
)
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);
12523 if (isPair (result
->aop
) && !offr
)
12524 fetchPairLong (getPairId (result
->aop
), left
->aop
, ic
, offl
);
12526 genMove_o (result
->aop
, offr
, left
->aop
, offl
, 2, true, isPairDead (PAIR_HL
, ic
), isPairDead (PAIR_DE
, ic
), true, true);
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)
12538 emitRsh2 (result
->aop
, size
, is_signed
);
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
)
12559 emitRsh2 (result
->aop
, size
, is_signed
);
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.
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 /*-----------------------------------------------------------------*/
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);
12597 emit3 (A_RR
, result
->aop
, 0);
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
;
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);
12616 emit3_o (A_LD
, result
->aop
, 0, ASMOP_ZERO
, 0);
12617 if (aopInReg (lowbyte
, 0, A_IDX
))
12618 emit3 (A_RRA
, 0, 0);
12620 emit3 (A_RR
, lowbyte
, 0);
12622 cheapMove (result
->aop
, 0, lowbyte
, 0, true);
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
;
12638 genMove_o (result
->aop
, 0, left
->aop
, 0, 2, isRegDead (A_IDX
, ic
), isPairDead (PAIR_HL
, ic
), isPairDead (PAIR_DE
, ic
), true, true);
12642 else if (getPairId (shiftaop
) == PAIR_HL
)
12645 emit3w (A_ADD
, ASMOP_HL
, ASMOP_HL
);
12647 else if (getPairId (shiftaop
) == PAIR_IY
)
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
)
12659 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
12664 else if (!IS_SM83
&& getPairId (shiftaop
) == PAIR_DE
)
12666 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
12668 emit3w (A_ADD
, ASMOP_HL
, ASMOP_HL
);
12669 emit3w (A_EX
, ASMOP_DE
, ASMOP_HL
);
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
)
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
);
12689 emit3_o (offset
? A_RL
: A_SLA
, shiftaop
, offset
, 0, 0);
12694 if (!use_b
&& !isRegDead (A_IDX
, ic
))
12697 /* Left is already in result - so now do the shift */
12700 if (!regalloc_dry_run
)
12702 emit2 ("ld %s, !immedbyte", use_b
? "b" : "a", (unsigned)shCount
);
12705 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
12707 if (requiresHL (shiftaop
))
12708 spillPair (PAIR_HL
);
12713 emit3_o (offset
? A_RL
: A_SLA
, shiftaop
, offset
, 0, 0);
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.
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
))
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);
12744 bool pushed_a
= false;
12745 if (!isRegDead (A_IDX
, ic
) || shiftaop
->regs
[A_IDX
] >= 0 && shiftaop
->regs
[A_IDX
] != result
->aop
->size
- 1)
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);
12758 if (shiftaop
!= result
->aop
)
12760 if (isPair (result
->aop
))
12761 fetchPairLong (getPairId (result
->aop
), shiftaop
, ic
, 0);
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 /*-----------------------------------------------------------------*/
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
;
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);
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
)
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
);
12819 cheapMove (result
->aop
, (free_reg
== ASMOP_A
? 1 : 0), free_reg
, 0, TRUE
);
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);
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
;
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);
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 */
12847 if (isPairDead(PAIR_DE
, ic
))
12865 emit2 ("ex (sp), hl");
12866 cost2 (1 + IS_RAB
, 19, 16, 15, 0, 14, 5, 5);
12872 /* --== generic implementations ==-- */
12873 if (!operandsEqu (result
, left
))
12874 { /* result is registers or left differs than result */
12875 bool pushed
= !isRegDead (A_IDX
, ic
);
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
);
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
)))
12897 else if (dead_hl
&&
12898 (left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, HL_IDX
)))
12900 else if (dead_de
&&
12901 (left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, DE_IDX
)))
12903 else if (!IS_SM83
&& !IY_RESERVED
&& isPairDead (PAIR_IY
, ic
) &&
12904 (left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, IY_IDX
)))
12909 if ((left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, HL_IDX
)))
12911 else if ((left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, BC_IDX
)))
12913 else if ((left
->aop
->type
!= AOP_REG
|| !aopInReg (left
->aop
, 0, DE_IDX
)))
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);
12923 _pop (tmp
->aopu
.aop_pairId
);
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 /*-----------------------------------------------------------------*/
12938 AccRol (int shCount
)
12940 shCount
&= 0x0007; // shCount : 0..7
12945 if (IS_SM83
|| IS_Z80N
)
12947 emit3 (A_SWAP
, ASMOP_A
, 0);
12950 emit3 (A_RLCA
, 0, 0);
12952 if (IS_SM83
|| IS_Z80N
)
12954 emit3 (A_SWAP
, ASMOP_A
, 0);
12955 emit3 (A_RRCA
, 0, 0);
12958 emit3 (A_RLCA
, 0, 0);
12960 emit3 (A_RLCA
, 0, 0);
12962 emit3 (A_RLCA
, 0, 0);
12966 if (IS_SM83
|| IS_Z80N
)
12968 emit3 (A_SWAP
, ASMOP_A
, 0);
12969 emit3 (A_RLCA
, 0, 0);
12972 emit3 (A_RRCA
, 0, 0);
12974 emit3 (A_RRCA
, 0, 0);
12976 emit3 (A_RRCA
, 0, 0);
12981 /*-----------------------------------------------------------------*/
12982 /* AccLsh - left shift accumulator by known count */
12983 /*-----------------------------------------------------------------*/
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
)
12994 emit3 (A_ADD
, ASMOP_A
, ASMOP_A
);
12997 /* rotate left accumulator */
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 /*-----------------------------------------------------------------*/
13009 shiftL1Left2Result (operand
*left
, int offl
, operand
*result
, int offr
, unsigned int shCount
, const iCode
*ic
)
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
))
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
)
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
);
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);
13052 if (!isRegDead (A_IDX
, ic
))
13054 cheapMove (ASMOP_A
, 0, left
->aop
, offl
, true);
13055 /* shift left accumulator */
13057 cheapMove (result
->aop
, offr
, ASMOP_A
, 0, true);
13058 if (!isRegDead (A_IDX
, ic
))
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);
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)
13075 cheapMove (ASMOP_A
, 0, result
->aop
, result
->aop
->size
- 1, true);
13076 emit2 ("and a, #0x%02x", topbytemask
);
13078 cheapMove (result
->aop
, result
->aop
->size
- 1, ASMOP_A
, 0, true);
13084 /*-----------------------------------------------------------------*/
13085 /* genlshTwo - left shift two bytes by known amount */
13086 /*-----------------------------------------------------------------*/
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
);
13101 emit2 ("bsla de, b");
13104 else if (shCount
>= 8)
13107 shiftL1Left2Result (left
, 0, result
, 1, shCount
, ic
);
13108 cheapMove (result
->aop
, 0, ASMOP_ZERO
, 0, isRegDead (A_IDX
, ic
));
13111 shiftL2Left2Result (left
, result
, shCount
, ic
);
13114 /*-----------------------------------------------------------------*/
13115 /* genRot1 - generates code for rotation of 8-bit values */
13116 /*-----------------------------------------------------------------*/
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);
13157 emit3_o (A_LD
, ASMOP_HL
, 1, ASMOP_HL
, 0);
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);
13167 emit3_o (A_LD
, ASMOP_DE
, 1, ASMOP_DE
, 0);
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
))
13179 if (!aopSame (result
->aop
, 0, left
->aop
, 0, 1))
13180 cheapMove (result
->aop
, 0, ASMOP_A
, 0, false);
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
))
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);
13201 if (!isRegDead (A_IDX
, ic
))
13203 cheapMove (ASMOP_A
, 0, left
->aop
, 0, true);
13205 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
13206 if (!isRegDead (A_IDX
, ic
))
13210 freeAsmop (left
, NULL
);
13211 freeAsmop (result
, NULL
);
13214 /*-----------------------------------------------------------------*/
13215 /* genRot - generates code for rotation */
13216 /*-----------------------------------------------------------------*/
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
))
13225 else if (IS_OP_LITERAL (right
) && operandLitValueUll (right
) % lbits
== 1)
13227 else if (IS_OP_LITERAL (right
) && operandLitValueUll (right
) % lbits
== lbits
- 1)
13229 else if (IS_OP_LITERAL (right
) && (operandLitValueUll (right
) % lbits
) * 2 == lbits
)
13232 wassertl (0, "Unsupported rotation.");
13235 /*------------------------------------------------------------------*/
13236 /* genLeftShiftLiteral - left shifting by known count for size <= 2 */
13237 /*------------------------------------------------------------------*/
13239 genLeftShiftLiteral (operand
*left
, operand
*right
, operand
*result
, const iCode
*ic
)
13241 unsigned int shCount
= ulFromVal (right
->aop
->aopu
.aop_lit
);
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);
13261 shiftL1Left2Result (left
, 0, result
, 0, shCount
, ic
);
13264 genlshTwo (result
, left
, shCount
, ic
);
13267 wassertl (0, "Shifting of longs should be handled by generic function.");
13273 freeAsmop (left
, NULL
);
13274 freeAsmop (result
, NULL
);
13277 /*-----------------------------------------------------------------*/
13278 /* genLeftShift - generates code for left shifting */
13279 /*-----------------------------------------------------------------*/
13281 genLeftShift (const iCode
*ic
)
13284 symbol
*tlbl
= 0, *tlbl1
= 0;
13285 operand
*left
, *right
, *result
;
13289 int shiftcount
= 0;
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
);
13309 /* Useful for the case of shifting a size > 2 value by a literal */
13310 shift_by_lit
= right
->aop
->type
== AOP_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
))
13328 else if (isRegDead (A_IDX
, ic
) && result
->aop
->regs
[A_IDX
] < 0 && left
->aop
->regs
[A_IDX
] < 0)
13330 else if (isRegDead (B_IDX
, ic
) && result
->aop
->regs
[B_IDX
] < 0 && left
->aop
->regs
[B_IDX
] < 0)
13332 else if (isRegDead (C_IDX
, ic
) && result
->aop
->regs
[C_IDX
] < 0 && left
->aop
->regs
[C_IDX
] < 0)
13334 else if (IS_Z80N
&& z80n_de
&& aopInReg (right
->aop
, 0, B_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");
13352 save_a_outer
= (!isRegDead (A_IDX
, ic
) && countreg
== A_IDX
&& !(shift_by_lit
&& shiftcount
== 1));
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
);
13371 shiftop
= left
->aop
;
13374 /* now move the left to the result if they are not the
13376 if (!sameRegs (shiftop
, left
->aop
) || shiftop
->type
== AOP_REG
)
13383 byteshift
= 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);
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
)
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
)
13427 if (requiresHL (shiftop
))
13428 spillPair (PAIR_HL
);
13432 regalloc_dry_run_state_scale
= shift_by_lit
? shiftcount
: 2;
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
);
13449 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
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
);
13462 size
-= 2, offset
+= 2;
13466 if (offset
>= byteshift
)
13468 if (aopInReg (shiftop
, offset
, A_IDX
))
13469 emit3 (started
? A_ADC
: A_ADD
, ASMOP_A
, ASMOP_A
);
13471 emit3_o (started
? A_RL
: A_SLA
, shiftop
, offset
, 0, 0);
13478 if (!(shift_by_lit
&& shiftcount
== 1))
13480 if (!regalloc_dry_run
)
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.
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.
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);
13510 bool pushed_a
= false;
13511 if (!isRegDead (A_IDX
, ic
) || shiftop
->regs
[A_IDX
] >= 0 && shiftop
->regs
[A_IDX
] != result
->aop
->size
- 1)
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);
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);
13529 freeAsmop (left
, NULL
);
13530 freeAsmop (right
, NULL
);
13531 freeAsmop (result
, NULL
);
13534 /*-----------------------------------------------------------------*/
13535 /* AccRsh - right shift accumulator by known count */
13536 /*-----------------------------------------------------------------*/
13538 AccRsh (int shCount
)
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);
13550 emit3 (A_SRL
, ASMOP_A
, 0);
13553 /*-----------------------------------------------------------------*/
13554 /* genrshOne - right shift one byte by known amount */
13555 /*-----------------------------------------------------------------*/
13557 genrshOne (operand
*result
, operand
*left
, int shCount
, int is_signed
, const iCode
*ic
)
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
);
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
))))
13593 cheapMove (ASMOP_A
, 0, left
->aop
, 0, true);
13595 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
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
);
13604 emit3 (is_signed
? A_SRA
: A_SRL
, result
->aop
, 0);
13610 cheapMove (ASMOP_A
, 0, left
->aop
, 0, true);
13612 emit3 (is_signed
? A_SRA
: A_SRL
, ASMOP_A
, 0);
13613 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
13619 /*-----------------------------------------------------------------*/
13620 /* shiftR1Left2Result - shift right one byte from left to result */
13621 /*-----------------------------------------------------------------*/
13623 shiftR1Left2Result (operand
*left
, int offl
, operand
*result
, int offr
, int shCount
, int sign
)
13625 cheapMove (ASMOP_A
, 0, left
->aop
, offl
, true);
13629 emit3 (sign
? A_SRA
: A_SRL
, ASMOP_A
, 0);
13633 cheapMove (result
->aop
, offr
, ASMOP_A
, 0, true);
13636 /*-----------------------------------------------------------------*/
13637 /* genrshTwo - right shift two bytes by known amount */
13638 /*-----------------------------------------------------------------*/
13640 genrshTwo (const iCode
*ic
, operand
*result
, operand
*left
, int shCount
, int sign
)
13643 aopInReg (result
->aop
, 0, DE_IDX
) && isRegDead (B_IDX
, ic
) &&
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");
13651 else if (shCount
>= 8)
13655 shiftR1Left2Result (left
, MSB16
, result
, LSB
, shCount
, sign
);
13657 cheapMove (result
->aop
, 0, left
->aop
, 1, isRegDead (A_IDX
, ic
));
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);
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);
13670 cheapMove (result
->aop
, 1, ASMOP_ZERO
, 0, true);
13673 shiftR2Left2Result (ic
, left
, LSB
, result
, LSB
, shCount
, sign
);
13676 /*-----------------------------------------------------------------*/
13677 /* genRightShiftLiteral - right shifting by known count */
13678 /*-----------------------------------------------------------------*/
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
);
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
);
13703 cheapMove (result
->aop
, size
, ASMOP_A
, 0, true);
13706 genMove (result
->aop
, ASMOP_ZERO
, isRegDead (A_IDX
, ic
), isPairDead (PAIR_HL
, ic
), false, true);
13713 genrshOne (result
, left
, shCount
, sign
, ic
);
13716 genrshTwo (ic
, result
, left
, shCount
, sign
);
13719 wassertl (0, "Asked to shift right a long which should be handled in generic right shift function.");
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 /*-----------------------------------------------------------------*/
13733 genRightShift (const iCode
* ic
)
13735 operand
*right
, *left
, *result
;
13737 int size
, offset
, first
= 1;
13740 bool shift_by_lit
, shift_by_one
, shift_by_zero
;
13741 int shiftcount
= 0;
13742 int byteoffset
= 0;
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
);
13766 /* Useful for the case of shifting a size > 2 value by a literal */
13767 shift_by_lit
= right
->aop
->type
== AOP_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
)))))
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");
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
);
13818 shiftop
= left
->aop
;
13821 /* now move the left to the shiftop if they are not the
13823 if (!sameRegs (shiftop
, left
->aop
) || shiftop
->type
== AOP_REG
)
13826 size
= shiftop
->size
;
13828 if (!is_signed
&& shift_by_lit
)
13830 byteoffset
= shiftcount
/ 8;
13832 soffset
= byteoffset
;
13833 size
-= byteoffset
;
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);
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
;
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;
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
))
13889 emit3 (A_CP
, ASMOP_A
, ASMOP_A
);
13892 emit2 (shiftop
->aopu
.aop_reg
[offset
- 1]->rIdx
== L_IDX
? "rr hl" : "rr de");
13894 size
-= 2, offset
-= 2;
13896 else if (!is_signed
&& first
&& byteoffset
--) // Skip known 0 bytes
13900 emit3_o (is_signed
? A_SRA
: A_SRL
, shiftop
, offset
, 0, 0);
13906 emit3_o (A_RR
, shiftop
, offset
, 0, 0);
13913 if (!regalloc_dry_run
)
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.
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.
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 /*-----------------------------------------------------------------*/
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
))
13959 emit3(A_RRA
, 0, 0);
13960 emit3(A_SBC
, ASMOP_A
, ASMOP_A
);
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
));
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 /*-----------------------------------------------------------------*/
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 */
14002 emit2 ("ld a, !mems", _pairs
[pair
].name
);
14003 regalloc_dry_run_cost
+= (pair
== PAIR_IX
|| pair
== PAIR_IY
) ? 3 : 1;
14005 unpackMaskA (etype
, blen
);
14006 cheapMove (result
->aop
, offset
++, ASMOP_A
, 0, true);
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
))
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
);
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
);
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);
14046 emit2 ("inc %s", _pairs
[pair
].name
);
14047 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14048 _G
.pairs
[pair
].offset
++;
14053 /* Handle the partial byte at the end */
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);
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);
14069 _G
.pairs
[pair
].offset
--;
14072 if (offset
< rsize
)
14076 if (SPEC_USIGN (etype
))
14077 source
= ASMOP_ZERO
;
14080 /* signed bit-field: sign extension with 0x00 or 0xff */
14081 emit3 (A_RLA
, 0, 0);
14082 emit3 (A_SBC
, ASMOP_A
, ASMOP_A
);
14087 cheapMove (result
->aop
, offset
++, source
, 0, true);
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);
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
)
14115 emit2 (val
> 0 ? "inc %s" : "dec %s", _pairs
[pair
].name
);
14116 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
14125 if (save_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);
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);
14136 cost2 (2, 15, 10, 4, 0, 8, 2, 2);
14137 if (save_extrapair
)
14142 /*------------------------------------------------------------------*/
14143 /* init_stackop - initialize asmop for stack location */
14144 /*------------------------------------------------------------------*/
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
;
14155 stackop
->type
= AOP_STK
;
14157 stackop
->valinfo
.anything
= true;
14160 /*-----------------------------------------------------------------*/
14161 /* genPointerGet - generate code for pointer get */
14162 /*-----------------------------------------------------------------*/
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.
14191 if ((IS_SM83
|| IY_RESERVED
) && requiresHL (result
->aop
) && size
> 1 && result
->aop
->type
!= AOP_REG
)
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));
14198 cheapMove (result
->aop
, 0, ASMOP_A
, 0, true);
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);
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);
14214 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
14217 else if (!IS_SM83
&& (left
->aop
->type
== AOP_IMMD
) && getPartPairId (result
->aop
, 0) != PAIR_INVALID
&& getPartPairId (result
->aop
, 2) != PAIR_INVALID
)
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);
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);
14231 cost2 (4, 20, 18, 13, 0, 12, 6, 6);
14234 else if (left
->aop
->type
== AOP_STL
&& !bit_field
&& size
<= 4)
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
));
14243 wassert (!rightval
);
14245 if (isPair (left
->aop
) && size
== 1 && !bit_field
&& !rightval
)
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);
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);
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);
14276 if (getPairId (left
->aop
) == PAIR_IY
&& !bit_field
&& rightval_in_range
)
14280 if (IS_RAB
&& getPartPairId (result
->aop
, 0) == PAIR_HL
)
14282 emit2 ("ld hl, %d (iy)", rightval
);
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);
14300 if (surviving_a
&& !pushed_a
)
14301 _push (PAIR_AF
), pushed_a
= TRUE
;
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)
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
))
14329 if(!isPairDead (PAIR_DE
, ic
))
14331 if(!isPairDead (PAIR_BC
, ic
))
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);
14345 fetchPair (PAIR_HL
, left
->aop
);
14346 emit2 ("lea de, ix, !immed%d", fp_offset
);
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);
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);
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
);
14379 emit2 ("ld bc, !immedword", (unsigned)size
);
14380 cost2 (3, 10, 9, 6, 12, 6, 3, 3);
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
))
14389 if(!isPairDead (PAIR_DE
, ic
))
14391 if(!isPairDead (PAIR_HL
, ic
))
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
);
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;
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);
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);
14437 fetchPair (pair
, left
->aop
);
14440 /* if bit then unpack */
14443 offsetPair (pair
, extrapair
, !isPairDead (extrapair
, ic
), rightval
);
14444 genUnpackBits (result
, pair
, ic
);
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
);
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
);
14465 else if (IS_EZ80_Z80
&& getPairId (result
->aop
) == PAIR_HL
&& !rightval
)
14467 emit2 ("ld hl, !*hl");
14470 else if (aopInReg (result
->aop
, 1, A_IDX
))
14472 offsetPair (pair
, extrapair
, !isPairDead (extrapair
, ic
), rightval
+ 1);
14474 if (!regalloc_dry_run
)
14475 aopPut (result
->aop
, "!*hl", 0);
14476 regalloc_dry_run_cost
+= 3;
14480 if (surviving_a
&& !pushed_a
)
14481 _push (PAIR_AF
), pushed_a
= TRUE
;
14482 offsetPair (pair
, extrapair
, !isPairDead (extrapair
, ic
), rightval
);
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
);
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
;
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
)
14514 else if (result
->aop
->aopu
.aop_reg
[i
]->rIdx
== H_IDX
)
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
)
14525 _moveFrom_tpair_ (result
->aop
, offset
, pair
);
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.
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
);
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;
14570 if (offset
!= l
&& offset
!= h
)
14571 _moveFrom_tpair_ (result
->aop
, offset
, pair
);
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.
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
);
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;
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
);
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
)
14657 size
= result
->aop
->size
;
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);
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);
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
)
14705 freeAsmop (left
, NULL
);
14706 freeAsmop (result
, NULL
);
14710 isRegOrLit (asmop
* aop
)
14712 if (aop
->type
== AOP_REG
|| aop
->type
== AOP_LIT
|| aop
->type
== AOP_IMMD
)
14718 /*-----------------------------------------------------------------*/
14719 /* genPackBits - generates code for packed bit storage */
14720 /*-----------------------------------------------------------------*/
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 */
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;
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
);
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);
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;
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);
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)
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
;
14802 extraPair
= PAIR_BC
;
14803 if (getPairId (right
->aop
) != PAIR_BC
|| !isLastUse (ic
, right
))
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;
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;
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);
14848 _G
.pairs
[pair
].offset
++;
14854 /* If there was a partial byte at the end */
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);
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);
14884 emit2 ("or a, !immedbyte", (unsigned)litval
);
14885 cost2 (2, 7, 6, 4, 8, 4, 2, 2);
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
;
14902 extraPair
= PAIR_BC
;
14903 if (getPairId (right
->aop
) != PAIR_BC
|| !isLastUse (ic
, right
))
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;
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);
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;
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);
14951 _G
.pairs
[pair
].offset
--;
14955 /*-----------------------------------------------------------------*/
14956 /* genPointerSet - stores the value into a pointer location */
14957 /*-----------------------------------------------------------------*/
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
;
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));
14995 /* Handle the exceptions first */
14996 if (isPair (result
->aop
) && size
== 1 && !bit_field
)
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
15010 ld_cost (ASMOP_A
, 0, right
->aop
, 0, true);
15011 cost2 (1, 7, 7, 7, 8, 6 , 2, 2); // Assume ld (rr), a
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
15026 /* Rematerialized stack location */
15027 if (result
->aop
->type
== AOP_STL
&& !bit_field
&& size
<= 4)
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
));
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
))
15043 if(!isPairDead (PAIR_BC
, ic
))
15045 if(!isPairDead (PAIR_HL
, ic
))
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);
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
))
15062 if(!isPairDead (PAIR_BC
, ic
))
15064 if(!isPairDead (PAIR_DE
, ic
))
15069 if (getPairId (result
->aop
) == PAIR_IY
&& !bit_field
)
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
15081 cost2 (3, 19, 15, 10, 0, 10, 4, 5); // ld d (iy), r
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
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;
15107 emit3w (A_INC
, ASMOP_HL
, 0);
15108 emit3w (A_INC
, ASMOP_HL
, 0);
15109 _G
.pairs
[PAIR_HL
].offset
++;
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);
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);
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);
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);
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);
15158 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
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
))
15167 fetchPairLong (pairId
, right
->aop
, ic
, 0);
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);
15175 cost2 (4, 20, 19, 15, 0, 12, 6, 6);
15176 if (isLitWord (right
->aop
))
15179 fetchPairLong (pairId
, right
->aop
, ic
, 2);
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;
15188 if (getPairId (result
->aop
) != pairId
&&
15189 (right
->aop
->regs
[_pairs
[pairId
].l_idx
] >= 0 || right
->aop
->regs
[_pairs
[pairId
].h_idx
] >= 0))
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
);
15198 if (!isPairDead (pairId
, ic
) && getPairId (result
->aop
) != 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 */
15215 genPackBits (getSpec (operandType (result
)->next
), right
, pairId
, ic
);
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;
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
++;
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);
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);
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);
15269 emit2 ("ld !mems, a", _pairs
[pairId
].name
);
15270 cost2 (1, 7, 7, 7, 8, 6, 2, 2);
15276 if (right
->aop
->regs
[_pairs
[pairId
].l_idx
] >= offset
|| right
->aop
->regs
[_pairs
[pairId
].h_idx
] >= offset
)
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
--;
15298 freeAsmop (right
, NULL
);
15299 freeAsmop (result
, NULL
);
15302 /*-----------------------------------------------------------------*/
15303 /* genIfx - generate code for Ifx statement */
15304 /*-----------------------------------------------------------------*/
15306 genIfx (iCode
*ic
, iCode
*popIc
)
15308 operand
*cond
= IC_COND (ic
);
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!
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");
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");
15342 /* get the value into acc */
15343 else if (cond
->aop
->type
!= AOP_CRY
)
15344 _toBoolean (cond
, !popIc
);
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
);
15356 genIfxJump (ic
, popIc
? "a" : "nz");
15362 freeAsmop (cond
, NULL
);
15367 /*-----------------------------------------------------------------*/
15368 /* genAddrOf - generates code for address of */
15369 /*-----------------------------------------------------------------*/
15371 genAddrOf (const iCode
* ic
)
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);
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
);
15390 pair
= (getPairId (IC_RESULT (ic
)->aop
) == PAIR_IY
) ? PAIR_IY
: PAIR_HL
;
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);
15398 setupPairFromSP (pair
, sp_offset
);
15402 pair
= getPairId (IC_RESULT (ic
)->aop
);
15403 if (pair
== PAIR_INVALID
)
15405 pair
= IS_SM83
? PAIR_DE
: PAIR_HL
;
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);
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 /*-----------------------------------------------------------------*/
15424 genAssign (const iCode
*ic
)
15426 operand
*result
, *right
;
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
)))
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)");
15448 /* if the result is a bit */
15449 if (result
->aop
->type
== AOP_CRY
)
15451 wassertl (0, "Tried to assign to a bit");
15455 size
= result
->aop
->size
;
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
);
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
);
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
)
15494 if (IS_TLCS90
) // f needs to be preserved for tlcs90.
15497 emit2 ("ld a, 0(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);
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);
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
)
15536 fetchPair (pair
, right
->aop
);
15537 commitPair (result
->aop
, pair
, ic
, FALSE
);
15546 cheapMove (result
->aop
, size
, ASMOP_A
, 0, true);
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);
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
);
15570 aopGet (result
->aop
, LSB
, FALSE
);
15572 regalloc_dry_run_cost
+= 8; // Todo: More exact cost here!
15576 emit2 ("ld a, !mems", "de");
15577 cost2 (1 + IS_TLCS90
, 7, 6, 6, 8, 6, 2, 2);
15580 emit2 ("!lldahli");
15582 regalloc_dry_run_cost
+= 3;
15586 emit2 ("ld !*hl, a");
15587 cost2 (1 + IS_TLCS90
, 7, 7, 7, 8, 6, 2, 2);
15590 spillPair (PAIR_HL
);
15594 // ldir could overwrite if areas overlap.
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
)
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
);
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
;
15631 cyclecost_n
= 30 * size
;
15633 cyclecost_n
= 18 * size
;
15635 cyclecost_n
= 38 * size
;
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.
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;
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;
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
);
15655 l_better
= (cyclecost_l
< cyclecost_n
|| cyclecost_l
== cyclecost_n
&& sizecost_l
< sizecost_n
);
15666 if (result
->aop
->type
== AOP_STK
|| result
->aop
->type
== AOP_EXSTK
)
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
);
15677 pointPairToAop (PAIR_DE
, result
->aop
, 0);
15679 if (right
->aop
->type
== AOP_STK
|| right
->aop
->type
== AOP_EXSTK
)
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;
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
++)
15698 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
15702 emit2 ("ld bc, !immed%d", size
);
15704 regalloc_dry_run_cost
+= 5;
15706 spillPair (PAIR_HL
);
15707 spillPair (PAIR_DE
);
15708 spillPair (PAIR_BC
);
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
));
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
)));
15732 cheapMove (result
->aop
, offset
, right
->aop
, offset
, isRegDead (A_IDX
, ic
));
15736 spillPair (PAIR_HL
);
15743 freeAsmop (right
, NULL
);
15744 freeAsmop (result
, NULL
);
15747 /*-----------------------------------------------------------------*/
15748 /* genJumpTab - generate code for jump table */
15749 /*-----------------------------------------------------------------*/
15751 genJumpTab (const iCode
*ic
)
15753 symbol
*jtab
= NULL
;
15754 operand
*jtcond
= IC_JTCOND (ic
);
15755 bool pushed_pair
= false;
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");
15777 emit2 ("ld hl, a(hl)");
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
))
15785 else if (jtcond
->aop
->type
== AOP_REG
&& jtcond
->aop
->aopu
.aop_reg
[0]->rIdx
== C_IDX
&& isPairDead (PAIR_BC
, ic
))
15787 else if ((pair
= getDeadPairId (ic
)) == PAIR_INVALID
)
15790 if (!isPairDead (pair
, ic
))
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);
15814 emit2 ("ld hl, 0(hl)");
15819 emit2 ("ld %s, !*hl", _pairs
[pair
].l
);
15820 cost2 (1, 7, 6, 5, 8, 6, 2, 2);
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
);
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 /*-----------------------------------------------------------------*/
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
);
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
)))
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;
15896 cheapMove (result
->aop
, result
->aop
->size
- 1, ASMOP_A
, 0, true);
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
));
15910 if (IS_BOOL (resulttype
))
15912 _castBoolean (right
);
15917 /* if they are the same size or less */
15918 if (result
->aop
->size
<= right
->aop
->size
)
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);
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)
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);
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);
15976 emit3 (A_SBC
, ASMOP_A
, ASMOP_A
);
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);
15992 freeAsmop (right
, NULL
);
15993 freeAsmop (result
, NULL
);
15996 /*-----------------------------------------------------------------*/
15997 /* genReceive - generate code for a receive iCode */
15998 /*-----------------------------------------------------------------*/
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
);
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
])
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 /*-----------------------------------------------------------------*/
16034 genDummyRead (const iCode
* ic
)
16039 op
= IC_RIGHT (ic
);
16040 if (op
&& IS_SYMOP (op
))
16042 aopOp (op
, ic
, FALSE
, FALSE
);
16045 size
= op
->aop
->size
;
16050 _moveA3 (op
->aop
, offset
);
16054 freeAsmop (op
, NULL
);
16058 if (op
&& IS_SYMOP (op
))
16060 aopOp (op
, ic
, FALSE
, FALSE
);
16063 size
= op
->aop
->size
;
16068 _moveA3 (op
->aop
, offset
);
16072 freeAsmop (op
, NULL
);
16076 /*-----------------------------------------------------------------*/
16077 /* genCritical - generate code for start of a critical sequence */
16078 /*-----------------------------------------------------------------*/
16080 genCritical (const iCode
* ic
)
16082 symbol
*tlbl
= regalloc_dry_run
? 0 : newiTempLabel (0);
16084 if (IS_SM83
|| IS_RAB
|| IS_TLCS90
)
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");
16101 //get interrupt enable flag IFF2 into P/O
16103 //disable interrupt
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
);
16120 if (z80_opts
.nmosZ80
)
16121 emit2 ("call ___sdcc_critical_enter");
16124 //get interrupt enable flag IFF2 into P/O
16126 //disable interrupt
16129 regalloc_dry_run_cost
+= 3;
16131 if (!regalloc_dry_run
) // _push unbalances _G.stack.pushed.
16134 cost2 (1, 11, 11, 10, 16, 8, 3, 4);
16138 /*-----------------------------------------------------------------*/
16139 /* genEndCritical - generate code for end of a critical sequence */
16140 /*-----------------------------------------------------------------*/
16142 genEndCritical (const iCode
* ic
)
16144 symbol
*tlbl
= regalloc_dry_run
? 0 : newiTempLabel (0);
16146 if (IS_SM83
|| IS_TLCS90
|| IS_RAB
)
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
));
16161 emitLabelSpill (tlbl
);
16163 regalloc_dry_run_cost
+= 4;
16164 freeAsmop (IC_RIGHT (ic
), NULL
);
16169 if (!regalloc_dry_run
) // _pop unbalances _G.stack.pushed.
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
));
16179 emit2 ("!tlabeldef", labelKey2num ((tlbl
->key
)));
16180 genLine
.lineCurr
->isLabel
= 1;
16182 regalloc_dry_run_cost
+= 4;
16188 /** Maximum number of bytes to emit per line. */
16192 /** Context for the byte output chunker. */
16195 unsigned char buffer
[DBEMIT_MAX_RUN
];
16200 /** Flushes a byte chunker by writing out all in the buffer and
16204 _dbFlush (DBEMITCTX
* self
)
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
]);
16222 /** Write out another byte, buffering until a decent line is
16226 _dbEmit (DBEMITCTX
* self
, int c
)
16228 if (self
->pos
== DBEMIT_MAX_RUN
)
16232 self
->buffer
[self
->pos
++] = c
;
16235 /** Context for a simple run length encoder. */
16239 unsigned char buffer
[128];
16241 /** runLen may be equivalent to pos. */
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.
16255 _rleCommit (RLECTX
* self
)
16258 if (self
->pos
!= 0)
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
]);
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.
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
16296 _rleAppend (RLECTX
* self
, unsigned c
)
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
16306 if (self
->runLen
> RLE_CHANGE_COST
)
16308 /* Yes, worthwhile. */
16309 /* Commit whatever was in the buffer. */
16311 emit2 ("!db !immed-%u, !immedbyte", self
->runLen
, self
->last
);
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
)
16323 self
->buffer
[self
->pos
++] = self
->last
;
16331 if (self
->runLen
>= RLE_MAX_BLOCK
)
16333 /* Commit whatever was in the buffer. */
16336 emit2 ("!db !immed-%u, !immedbyte", self
->runLen
, self
->last
);
16344 _rleFlush (RLECTX
* self
)
16346 _rleAppend (self
, -1);
16353 /** genArrayInit - Special code for initialising an array with constant
16358 genArrayInit (iCode
* ic
)
16360 literalList
*iLoop
;
16362 int elementSize
= 0, eIndex
, i
;
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
))
16380 if (!isPairDead (PAIR_DE
, ic
))
16385 if (!isPairDead (PAIR_BC
, ic
))
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
);
16412 printTypeChainRaw (type
, NULL
);
16413 wassertl (0, "Can't determine element size in genArrayInit.");
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
16427 This works well for mixed char data, and for random int and long
16434 for (i
= 0; i
< ix
; i
++)
16438 unsigned char c
[sizeof(unsigned long long)];
16440 unsigned long long ull
;
16445 if (iLoop
->isFloat
)
16446 buf
.f
= iLoop
->value
.f64
;
16448 buf
.f
= iLoop
->value
.ull
;
16452 if (iLoop
->isFloat
)
16453 buf
.ull
= (isBool
) ? !!iLoop
->value
.f64
: (unsigned long long)iLoop
->value
.f64
;
16455 buf
.ull
= (isBool
) ? !!iLoop
->value
.ull
: iLoop
->value
.ull
;
16458 #ifdef WORDS_BIGENDIAN
16459 for (eIndex
= elementSize
-1; eIndex
>= 0; eIndex
--)
16461 for (eIndex
= 0; eIndex
< elementSize
; eIndex
++)
16463 _rleAppend (&rle
, buf
.c
[eIndex
]);
16466 iLoop
= iLoop
->next
;
16470 /* Mark the end of the run. */
16471 emit2 (".db !zero");
16484 freeAsmop (IC_LEFT (ic
), NULL
);
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
};
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
};
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
};
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
));
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. */
16568 cheapMove (ASMOP_H
, 0, from
->aop
, 1, true);
16569 fetchPair (PAIR_DE
, to
->aop
);
16570 cheapMove (ASMOP_L
, 0, from
->aop
, 0, true);
16576 genBuiltInMemcpy (const iCode
*ic
, int nparams
, operand
**pparams
)
16579 operand
*from
, *to
, *count
;
16580 bool saved_BC
= FALSE
, saved_DE
= FALSE
, saved_HL
= FALSE
;
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];
16593 if (pparams
[2]->aop
->type
!= AOP_LIT
)
16595 else if (!(n
= (unsigned int) ulFromVal (pparams
[2]->aop
->aopu
.aop_lit
))) /* Check for zero length copy. */
16598 if (!isPairDead (PAIR_HL
, ic
))
16603 if (!isPairDead (PAIR_DE
, ic
))
16608 if (!isPairDead (PAIR_BC
, ic
) && n
> 2)
16614 setupForMemcpy (ic
, to
, from
, count
);
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);
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
++)
16639 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
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
16665 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16667 if (!regalloc_dry_run
)
16669 const symbol
*tlbl2
= newiTempLabel (0);
16672 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
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);
16686 cost2 (2, 16, 12, 10, 0 , 14, 5, 4);
16687 emit2 ("jp LO, !tlabel", labelKey2num (tlbl2
->key
));
16689 regalloc_dry_run_cost
+= 3;
16694 regalloc_dry_run_cost
+= 2;
16699 spillPair (PAIR_HL
);
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. */
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
};
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
);
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
);
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
)
16742 fetchPair (PAIR_HL
, dst
->aop
);
16743 if (dst
->aop
->type
== AOP_EXSTK
)
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);
16752 if (requiresHL (c
->aop
))
16754 cheapMove (ASMOP_A
, 0, c
->aop
, 0, true);
16755 if (requiresHL (c
->aop
))
16762 genBuiltInMemset (const iCode
*ic
, int nParams
, operand
**pparams
)
16764 operand
*dst
, *c
, *n
;
16765 bool direct_c
, direct_cl
;
16767 bool preinc
= FALSE
;
16768 unsigned long sizecost_ldir
, sizecost_direct
, sizecost_loop
;
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");
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
)))
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.
16816 setupForMemset (ic
, dst
, c
, direct_c
);
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);
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
);
16837 if (!isRegDead (B_IDX
, ic
))
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
)
16858 emit2 ("ld !*hl, %s", aopGet (direct_cl
? c
->aop
: ASMOP_A
, 0, FALSE
));
16864 emit2 ("ld !*hl, %s", aopGet (direct_cl
? c
->aop
: ASMOP_A
, 0, FALSE
));
16867 emit2 ("djnz !tlabel", labelKey2num (tlbl1
->key
));
16869 regalloc_dry_run_cost
+= (double_loop
? 6 : 4);
16871 else // Use ldir / lsidr
16890 fetchPair (PAIR_DE
, dst
->aop
);
16891 pointPairToAop (PAIR_HL
, c
->aop
, 0);
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)
16903 emit3 (A_LD
, ASMOP_E
, ASMOP_L
);
16904 emit3 (A_LD
, ASMOP_D
, ASMOP_H
);
16905 if (!IS_R3KA
|| optimize
.codeSpeed
)
16908 cost2 (1, 6, 4, 2, 8, 4, 1, 1);
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;
16921 spillPair (PAIR_HL
);
16923 freeAsmop (n
, NULL
);
16924 freeAsmop (c
, NULL
);
16925 freeAsmop (dst
, NULL
);
16934 /* No need to assign result - would have used ordinary memset() call instead. */
16938 genBuiltInStrcpy (const iCode
*ic
, int nParams
, operand
**pparams
)
16940 operand
*dst
, *src
;
16941 bool saved_BC
= FALSE
, saved_DE
= FALSE
, saved_HL
= FALSE
;
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.");
16954 for (i
= 0; i
< nParams
; i
++)
16955 aopOp (pparams
[i
], ic
, FALSE
, FALSE
);
16957 if (!isPairDead (PAIR_HL
, ic
))
16962 if (!isPairDead (PAIR_BC
, ic
))
16967 if (!isPairDead (PAIR_DE
, ic
))
16973 setupForMemcpy (ic
, dst
, src
, 0);
16975 emit3 (A_XOR
, ASMOP_A
, ASMOP_A
);
16976 if (SomethingReturned
)
16978 if (!regalloc_dry_run
)
16980 symbol
*tlbl
= newiTempLabel (NULL
);
16982 emit2 ("cp a, !*hl");
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
));
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
);
17019 genBuiltInStrncpy (const iCode
*ic
, int nparams
, operand
**pparams
)
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.");
17036 if (!ulFromVal (n
->aop
->aopu
.aop_lit
))
17039 if (!isPairDead (PAIR_HL
, ic
))
17044 if (!isPairDead (PAIR_BC
, ic
))
17049 if (!isPairDead (PAIR_DE
, ic
))
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);
17066 emit2 ("cp a,!*hl");
17068 emit2 (IS_RAB
? "jp LZ, !tlabel" : "jp PO, !tlabel", labelKey2num (tlbl1
->key
));
17069 emit2 ("jr NZ, !tlabel", labelKey2num (tlbl2
->key
));
17073 emit2 (IS_RAB
? "jp LO, !tlabel" : "jp PE, !tlabel", labelKey2num (tlbl3
->key
));
17076 regalloc_dry_run_cost
+= 14;
17078 spillPair (PAIR_HL
);
17080 restoreRegs (0, saved_DE
, saved_BC
, saved_HL
, 0, ic
);
17083 freeAsmop (n
, NULL
);
17084 freeAsmop (s2
, NULL
);
17085 freeAsmop (s1
, NULL
);
17089 genBuiltInStrchr (const iCode
*ic
, int nParams
, operand
**pparams
)
17092 bool saved_BC
= FALSE
, saved_DE
= FALSE
, saved_HL
= FALSE
;
17094 bool SomethingReturned
;
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.");
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
);
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
)))
17128 else if (c
->aop
->type
== AOP_LIT
&& optimize
.codeSize
)
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
))
17140 if (pair
== PAIR_BC
&& !isPairDead (PAIR_BC
, ic
))
17145 if ((pair
== PAIR_DE
|| !direct_c
) && !isPairDead (PAIR_DE
, ic
))
17152 cheapMove (aop_c
, 0, c
->aop
, 0, true);
17153 fetchPair (pair
, s
->aop
);
17155 if (!isRegDead (A_IDX
, ic
))
17158 if (!regalloc_dry_run
)
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
));
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
)
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 /*-----------------------------------------------------------------*/
17190 genBuiltIn (iCode
*ic
)
17192 operand
*bi_parms
[MAX_BUILTIN_ARGS
];
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
);
17227 wassertl (0, "Unknown builtin function encountered");
17231 /*-------------------------------------------------------------------------------------*/
17232 /* genZ80iCode - generate code for Z80 based controllers for a single iCode instruction*/
17233 /*-------------------------------------------------------------------------------------*/
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
17243 if (resultRemat (ic
))
17245 emitDebug ("; skipping iCode since result will be rematerialized");
17251 emitDebug ("; skipping generated iCode");
17255 /* depending on the operation */
17259 emitDebug ("; genNot");
17264 emitDebug ("; genCpl");
17269 emitDebug ("; genUminus");
17274 emitDebug ("; genIpush");
17278 case IPUSH_VALUE_AT_ADDRESS
:
17279 emitDebug ("; genPointerPush");
17280 genPointerPush (ic
);
17285 emitDebug ("; genCall");
17290 emitDebug ("; genFunction");
17295 emitDebug ("; genEndFunction");
17296 genEndFunction (ic
);
17300 emitDebug ("; genRet");
17305 emitDebug ("; genLabel");
17310 emitDebug ("; genGoto");
17315 emitDebug ("; genPlus");
17320 emitDebug ("; genMinus");
17321 genMinus (ic
, ic
->next
->op
== IFX
? ic
->next
: 0);
17325 emitDebug ("; genMult");
17330 emitDebug ("; genDiv");
17335 emitDebug ("; genMod");
17340 emitDebug ("; genCmpGt");
17341 genCmpGt (ic
, ifxForOp (IC_RESULT (ic
), ic
));
17345 emitDebug ("; genCmpLt");
17346 genCmpLt (ic
, ifxForOp (IC_RESULT (ic
), ic
));
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");
17359 emitDebug ("; genCmpEq");
17360 genCmpEq (ic
, ifxForOp (IC_RESULT (ic
), ic
));
17364 emitDebug ("; genAndOp");
17369 emitDebug ("; genOrOp");
17374 emitDebug ("; genXor");
17375 genXor (ic
, ifxForOp (IC_RESULT (ic
), ic
));
17379 emitDebug ("; genOr");
17380 genOr (ic
, ifxForOp (IC_RESULT (ic
), ic
));
17384 emitDebug ("; genAnd");
17385 genAnd (ic
, ifxForOp (IC_RESULT (ic
), ic
));
17389 emitDebug ("; genInline");
17394 emitDebug ("; genGetAbit");
17399 emitDebug ("; genGetByte");
17404 emitDebug ("; genGetWord");
17409 emitDebug ("; genRot");
17414 emitDebug ("; genLeftShift");
17419 emitDebug ("; genRightShift");
17420 genRightShift (ic
);
17423 case GET_VALUE_AT_ADDRESS
:
17424 emitDebug ("; genPointerGet");
17425 genPointerGet (ic
);
17430 if (POINTER_SET (ic
))
17432 emitDebug ("; genPointerSet");
17433 genPointerSet (ic
);
17437 emitDebug ("; genAssign");
17443 emitDebug ("; genIfx");
17448 emitDebug ("; genAddrOf");
17453 emitDebug ("; genJumpTab");
17458 emitDebug ("; genCast");
17463 emitDebug ("; genReceive");
17468 if (ic
->builtinSEND
)
17470 emitDebug ("; genBuiltIn");
17475 emitDebug ("; genSend");
17481 emitDebug ("; genArrayInit");
17485 case DUMMY_READ_VOLATILE
:
17486 emitDebug ("; genDummyRead");
17491 emitDebug ("; genCritical");
17496 emitDebug ("; genEndCritical");
17497 genEndCritical (ic
);
17501 wassertl (0, "Unknown iCode");
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
;
17518 destroy_line_list ();
17519 freeTrace (&_G
.trace
.aops
);
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
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
17544 dryZ80Code (iCode
* lic
)
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
);
17558 /*-------------------------------------------------------------------------------------*/
17559 /* genZ80Code - generate code for Z80 based controllers for a block of instructions */
17560 /*-------------------------------------------------------------------------------------*/
17562 genZ80Code (iCode
* lic
)
17564 #ifdef DEBUG_DRY_COST
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
)
17590 debugFile
->writeCLine (ic
);
17591 if (!options
.noCcodeInAsm
)
17592 emit2 (";%s:%d: %s", ic
->filename
, ic
->lineno
, printCLine (ic
->filename
, ic
->lineno
));
17595 if (options
.iCodeInAsm
)
17597 const char *iLine
= printILine (ic
);
17598 emit2 (";ic:%d: %s", ic
->key
, iLine
);
17601 //regalloc_dry_run_cost = 0;
17602 regalloc_dry_run_cost_bytes
= 0;
17603 regalloc_dry_run_cost_states
= 0;
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
);
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
);
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
)
17630 _G
.flushStatics
= 0;
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.
17647 z80IsReturned(const char *what
)
17649 if (!strcmp(what
, "iy"))
17650 return (z80IsReturned ("iyl") || z80IsReturned ("iyh"));
17652 const asmop
*retaop
= aopRet (currFunc
->type
);
17656 for (int i
= 0; i
< retaop
->size
; i
++)
17657 if (!strcmp(retaop
->aopu
.aop_reg
[i
]->name
, what
))
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.
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
);
17678 for (int i
= 0; i
< argaop
->size
; i
++)
17679 if (!strcmp(argaop
->aopu
.aop_reg
[i
]->name
, what
))
17686 z80IsParmInCall(sym_link
*ftype
, const char *what
)
17691 for (i
= 1, args
= FUNC_ARGS (ftype
); args
; args
= args
->next
, i
++)
17692 if (z80IsRegArg(ftype
, i
, what
))